Skip to content

Commit 04ffa7b

Browse files
Added breadcrumb links to a category page (#11)
* Added breadcrumb links to a category page * Addressed PR issues * Fixing accessibility issues * Fixed warning
1 parent a2264b1 commit 04ffa7b

File tree

10 files changed

+103
-52
lines changed

10 files changed

+103
-52
lines changed

src/App.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11

2+
@import './theme/common';
3+
24
.app {
35
min-height: 100%;
46
display: flex;
57
flex-direction: column;
68

7-
$maxScrollWidth: 34px;
8-
99
&__header {
1010
height: 60px;
1111
flex: 0 0 auto;

src/Category.scss

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
11

2+
@import './theme/common';
3+
24
.category {
35
$block: &;
46

57
display: inline-flex;
68
flex-direction: column;
79
align-items: center;
810
height: 100%;
11+
padding-left: $maxScrollWidth;
12+
padding-right: calc(#{$maxScrollWidth} - 100vw + 100%);
13+
14+
#{$block}__breadcrumbs {
15+
margin-top: 20px;
16+
font-size: 15px;
17+
font-weight: bold;
18+
color: hsl(0, 0%, 45%);
19+
20+
#{$block}__breadcrumbseparator {
21+
color: hsl(0, 0, 70%);
22+
margin-left: 10px;
23+
margin-right: 10px;
24+
}
25+
}
926

1027
#{$block}__categoryname {
1128
flex: 0;
12-
padding: 50px 0px 80px;
29+
margin-top: 20px;
30+
margin-bottom: 80px;
1331
font-size: 26px;
1432
font-weight: bold;
1533
}

src/Category.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ function useCategoryProducts(categoryId: string | undefined, pageNum: number) {
1818
}, [categoryId]);
1919

2020
const [products] = useResolve(async () => {
21-
// during initial loading of categories categoryId mught be undefined
21+
// during initial loading of categories categoryId might be undefined
2222
if (categoryId) {
2323
const result = await loadCategoryProducts(categoryId, pageNum);
2424
setTotalPages(result.pagination.totalPages);
@@ -37,8 +37,9 @@ interface CategoryParams {
3737
export const Category: React.FC = () => {
3838
const params = useParams<CategoryParams>();
3939
const categorySlug = params.categorySlug;
40-
const { categoryBySlug } = useCategories();
41-
const category = categoryBySlug(categorySlug);
40+
const { categoryPathBySlug } = useCategories();
41+
const categoryPath = categoryPathBySlug(categorySlug);
42+
const category = categoryPath?.[categoryPath?.length - 1];
4243
const parsedPageNum = parseInt(params.pageNum!);
4344
const pageNum = isNaN(parsedPageNum) ? 1 : parsedPageNum;
4445

@@ -48,6 +49,16 @@ export const Category: React.FC = () => {
4849
<div>
4950
{category ? (
5051
<div className="category">
52+
<div className="category__breadcrumbs">
53+
{categoryPath?.map((category, index) => (
54+
<React.Fragment key={category.id}>
55+
{index > 0 && (
56+
<span className="category__breadcrumbseparator">{'>'}</span>
57+
)}
58+
<a className="category__breadcrumblink" href={createCategoryUrl(category.slug)}>{category.name}</a>
59+
</React.Fragment>
60+
))}
61+
</div>
5162

5263
<h1 className="category__categoryname">{category?.name ?? ' '}</h1>
5364

src/CompareOverlay.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11

2+
@import './theme/common';
3+
24
$overlayHeight: 100px;
35
$animLength: 0.2s;
4-
$maxScrollWidth: 34px;
56

67
.compareoverlay {
78
$block: &;

src/Pagination.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
text-decoration: none;
88

99
&--current {
10-
color: hsl(0, 0, 70%);
10+
color: hsl(0, 0, 45%);
1111
}
1212
}
1313

1414
&__ellipsis {
15-
color: hsl(0, 0, 70%);
15+
color: hsl(0, 0, 45%);
1616
}
1717
}

src/Product.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11

2+
@import './theme/common';
3+
24
.product {
35
$block: &;
46

57
height: 100%;
68
display: flex;
79
flex-direction: column;
810
align-items: center;
11+
padding-left: $maxScrollWidth;
12+
padding-right: calc(#{$maxScrollWidth} - 100vw + 100%);
913

1014
#{$block}__maincontainer {
1115
width: 800px;
1216
display: flex;
1317
flex-direction: row;
1418
margin-top: 60px;
19+
margin-bottom: 60px;
1520

1621
$imgSize: 400px;
1722

src/ProductThumbnail.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ export const ProductThumbnail: React.FC<ProductThumbnailProps> = (props) => {
1818
return (
1919
<div className="productthumbnail">
2020
<div className="productthumbnail__imgcontainer">
21-
<Link className="productthumbnail__imglink" to={productUrl} aria-label="productthumbnail__imglink">
21+
<Link className="productthumbnail__imglink" to={productUrl} aria-label={props.product.name}>
2222
<ProductMainImage product={props.product} size={160} />
2323
</Link>
2424
</div>
2525
<div className="productthumbnail__name">
26-
<Link className="productthumbnail__namelink" to={productUrl} aria-label="productthumbnail__namelink">
26+
<Link className="productthumbnail__namelink" to={productUrl}>
2727
{props.product.name}
2828
</Link>
2929
</div>

src/app-state.ts

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,46 @@ import constate from 'constate';
33
import { Category, loadCategoryTree, Product } from './service';
44
import { config } from './config';
55

6-
function flatTree(tree: Category[]): Category[] {
7-
return [
8-
...tree.map(c => ({ ...c, children: undefined })),
9-
...tree.flatMap(c => c.children ? flatTree(c.children) : []),
10-
];
6+
7+
function getCategoryPaths(categories: Category[]): { [categoryId: string]: Category[] } {
8+
const lastCat = categories[categories.length - 1];
9+
10+
let map: { [categoryId: string]: Category[] } = {
11+
[lastCat.slug]: [...categories]
12+
};
13+
14+
const childCats = lastCat.children ?? [];
15+
16+
for (const child of childCats) {
17+
map = { ...map, ...getCategoryPaths([...categories, child]) };
18+
}
19+
20+
return map;
21+
}
22+
23+
function mergeMaps(tree: Category[]): { [categoryId: string]: Category[] } {
24+
return tree.reduce((acc, c) => ({ ...acc, ...getCategoryPaths([c]) }), {});
1125
}
1226

1327
function useCategoriesState() {
14-
const [categoriesTree, setCategoriesTree] = useState<Category[]>();
15-
const [categoriesFlat, setCategoriesFlat] = useState<Category[]>();
28+
const [categoryPaths, setCategoryPaths] = useState<{ [categoryId: string]: Category[] }>();
1629

17-
const categoryBySlug = (slug: string) => {
18-
return categoriesFlat?.filter(c => c.slug === slug)[0];
19-
};
30+
const [categoriesTree, setCategoriesTree] = useState<Category[]>();
2031

2132
useEffect(() => {
2233
loadCategoryTree().then(result => {
2334
setCategoriesTree(result);
24-
setCategoriesFlat(flatTree(result));
35+
setCategoryPaths(mergeMaps(result));
2536
});
2637
}, []);
2738

39+
const categoryPathBySlug = (slug: string) => {
40+
return categoryPaths?.[slug];
41+
};
42+
2843
return {
2944
categoriesTree,
30-
categoriesFlat,
31-
categoryBySlug,
45+
categoryPathBySlug,
3246
};
3347
}
3448

src/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
export const config = {
3-
clientId: 'EdP3Gi1agyUF3yFS7Ngm8iyodLgbSR3wY4ceoJl0d2',
3+
clientId: 'HvmUtpjmMSYmWs7zR367WYETN2aj51yXzxrxoWXu0x',
44
stripeKey: 'pk_test_JwRX4cevuCysIEQrpwcbn3j8',
55
categoryPageSize: 8,
66
maxCompareProducts: 4,

src/theme/common.scss

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,40 @@
11

2-
$mainColor: #000000;
3-
$firstComplimentColor: #197C93;
4-
$secondComplimentColor: #228197;
5-
$thirdComplimentColor: #167A92;
2+
$mainColor: #000000;
3+
$firstComplimentColor: #197C93;
4+
$secondComplimentColor: #228197;
5+
$thirdComplimentColor: #167A92;
66

7-
$mainTextColor: #333333;
8-
$firstComplimentTextColor: #2D383C;
9-
$secondComplimentTextColor: #666666;
10-
$thirdComplimentTextColor: #565656;
11-
$fourthComplimentTextColor: #1F2532;
12-
$fifthComplimentTextColor: #EEEEEE;
7+
$mainTextColor: #333333;
8+
$firstComplimentTextColor: #2D383C;
9+
$secondComplimentTextColor: #666666;
10+
$thirdComplimentTextColor: #565656;
11+
$fourthComplimentTextColor: #1F2532;
12+
$fifthComplimentTextColor: #EEEEEE;
1313

14-
$mainNavigationColor: #FFFFFF;
14+
$mainNavigationColor: #FFFFFF;
1515

16-
$buttonFocusColor: #979797;
17-
$buttonActiveColor: #4C5666;
16+
$buttonFocusColor: #979797;
17+
$buttonActiveColor: #4C5666;
1818

19-
$mainBorderColor: #D0D0D0;
20-
$firstBorderColor: #D4D3D3;
21-
$secondBorderColor: #CCCCCC;
19+
$mainBorderColor: #D0D0D0;
20+
$firstBorderColor: #D4D3D3;
21+
$secondBorderColor: #CCCCCC;
2222

23-
$mainBackgroundColor: #FFFFFF;
24-
$firstComplimentBackground: #F3F3F3;
25-
$secondComplimentBackground: #F7F7F7;
26-
$thirdComplimentBackground: #F2F6FA;
27-
$forthComplimentBackground: #DBDBDB;
28-
$fifthComplimentBackground: #C5C5C5;
23+
$mainBackgroundColor: #FFFFFF;
24+
$firstComplimentBackground: #F3F3F3;
25+
$secondComplimentBackground: #F7F7F7;
26+
$thirdComplimentBackground: #F2F6FA;
27+
$forthComplimentBackground: #DBDBDB;
28+
$fifthComplimentBackground: #C5C5C5;
2929

30-
$accountTreeActive: #E1F0F7;
30+
$accountTreeActive: #E1F0F7;
3131

32-
$firstAccentColor: #78B13F;
32+
$firstAccentColor: #78B13F;
3333

34-
$mainErrorColor: #E00646;
34+
$mainErrorColor: #E00646;
3535

36-
$mobileWidth: 768px;
37-
$tabletWidth: 1092px;
36+
$maxScrollWidth: 34px;
37+
38+
$mobileWidth: 768px;
39+
$tabletWidth: 1092px;
3840

0 commit comments

Comments
 (0)