Skip to content

Commit

Permalink
Improve card mode
Browse files Browse the repository at this point in the history
Signed-off-by: Cintia Sanchez Garcia <[email protected]>
  • Loading branch information
cynthia-sg committed Aug 14, 2023
1 parent 3836b3f commit a94ee1e
Show file tree
Hide file tree
Showing 9 changed files with 317 additions and 146 deletions.
2 changes: 1 addition & 1 deletion web/src/hooks/useBreakpointDetect.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { throttle } from 'lodash';
import { useEffect, useState } from 'react';

import { Breakpoint } from '../types';
import throttle from '../utils/throttle';

const getDeviceConfig = (width: number): Breakpoint | undefined => {
if (width < 576) {
Expand Down
2 changes: 2 additions & 0 deletions web/src/layout/explore/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import CardCategory from './cardCategory';
import GridCategory from './gridCategory';

interface Props {
isSelected: boolean;
containerWidth: number;
fullDataReady: boolean;
data: CategoriesData;
Expand All @@ -29,6 +30,7 @@ const Content = memo(function Content(props: Props) {
</div>
<div className={props.selectedViewMode === ViewMode.Card ? 'd-block' : 'd-none'}>
<CardCategory
isVisible={props.isSelected && props.selectedViewMode === ViewMode.Card}
fullDataReady={props.fullDataReady}
data={props.data}
categories_overridden={props.categories_overridden}
Expand Down
22 changes: 3 additions & 19 deletions web/src/layout/explore/cardCategory/CardCategory.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
max-width: 270px;
min-width: 270px;
font-size: 0.8rem;
top: 1rem;
bottom: 1rem;
height: calc(100vh - 2rem);
}

.truncateWrapper {
Expand Down Expand Up @@ -35,22 +38,3 @@
text-decoration: underline;
background-color: rgba(0, 0, 0, 0.035);
}

.card {
height: 237px;
font-size: 90%;
cursor: pointer;
}

.card :global(.badge) {
font-size: 65%;
}

.card :global(.accepted-date) {
display: flex !important;
}

.card:hover {
border-color: var(--bs-primary) !important;
box-shadow: 0px 0px 5px 0px var(--bs-focus-ring-color);
}
2 changes: 1 addition & 1 deletion web/src/layout/explore/cardCategory/CardTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { throttle } from 'lodash';
import { useEffect, useRef, useState } from 'react';

import throttle from '../../../utils/throttle';
import styles from './CardTitle.module.css';

interface Props {
Expand Down
47 changes: 47 additions & 0 deletions web/src/layout/explore/cardCategory/Content.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.title {
font-size: 0.8rem;
min-width: 0;
scroll-margin: 1rem;
}

.card {
height: 237px;
font-size: 90%;
cursor: pointer;
}

.card :global(.badge) {
font-size: 65%;
}

.card :global(.accepted-date) {
display: flex !important;
.title {
font-size: 0.8rem;
min-width: 0;
}

.card {
height: 237px;
font-size: 90%;
cursor: pointer;
}

.card :global(.badge) {
font-size: 65%;
}

.card :global(.accepted-date) {
display: flex !important;
}

.card:hover {
border-color: var(--bs-primary) !important;
box-shadow: 0px 0px 5px 0px var(--bs-focus-ring-color);
}
}

.card:hover {
border-color: var(--bs-primary) !important;
box-shadow: 0px 0px 5px 0px var(--bs-focus-ring-color);
}
136 changes: 136 additions & 0 deletions web/src/layout/explore/cardCategory/Content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { compact, orderBy, throttle } from 'lodash';
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { useNavigate, useOutletContext } from 'react-router-dom';

import { COLORS } from '../../../data';
import { BaseItem, Item, OutletContext } from '../../../types';
import { CategoriesData } from '../../../utils/prepareData';
import { convertStringSpaces, Menu } from '.';
import Card from './Card';
import styles from './Content.module.css';

interface Props {
menu: Menu;
data: CategoriesData;
isVisible: boolean;
selectedSection?: {
category: string;
subcategory: string;
};
}

const SCROLL_MARGIN = 20;

const findClosestNumberIndex = (arr: number[], num: number) => {
let closestIndex = arr[0];
for (let i = 0; i < arr.length; i++) {
if (arr[i] > num) {
break;
}
closestIndex = i;
}

return closestIndex;
};

const prevItemsInKeys = (menu: Menu, currentCatIndex: number): number => {
if (currentCatIndex === 0) {
return 0;
} else {
let items = 0;
for (let i = 0; i < currentCatIndex; i++) {
items = items + menu[Object.keys(menu)[i]].length;
}
return items - 1;
}
};

const Content = (props: Props) => {
const navigate = useNavigate();
const { updateActiveItemId } = useOutletContext() as OutletContext;
const titlesRef = useRef<Array<HTMLDivElement | null>>([]);
const [currentOffsets, setCurrentOffsets] = useState<number[]>([]);
const bgListColor = COLORS[1];

const sortItems = (firstCategory: string, firstSubcategory: string): BaseItem[] => {
return orderBy(
props.data[firstCategory][firstSubcategory].items,
[(item: BaseItem) => item.name.toString()],
'asc'
);
};
useEffect(() => {
const handleScroll = throttle(() => {
if (props.isVisible) {
const scrollYPosition = window.scrollY;
const index = findClosestNumberIndex(currentOffsets, scrollYPosition);
const id = titlesRef.current[index]?.id;
if (id && props.selectedSection) {
const currentSelection = `${convertStringSpaces(props.selectedSection.category)}/${convertStringSpaces(
props.selectedSection.subcategory
)}`;
if (id !== currentSelection) {
navigate(
{ ...location, hash: id },
{
replace: true,
}
);
}
}
}
}, 200);

window.addEventListener('scroll', handleScroll, { passive: true });
return () => window.removeEventListener('scroll', handleScroll);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentOffsets, props.isVisible]);

useLayoutEffect(() => {
const offsets: number[] = titlesRef.current.map((el) => (el ? el.offsetTop - SCROLL_MARGIN : 0));
setCurrentOffsets(compact(offsets)); // Remove values 0 when we have less cat/subcat than before
}, [props.menu]);

return (
<>
{Object.keys(props.menu).map((cat: string, categoryIndex: number) => {
return (
<div key={`list_cat_${cat}`}>
{props.menu[cat].map((subcat: string, subcategoryIndex: number) => {
return (
<div key={`list_subcat_${subcat}`}>
<div
id={convertStringSpaces(`${cat}/${subcat}`)}
ref={(el: HTMLDivElement | null) => {
titlesRef.current[prevItemsInKeys(props.menu, categoryIndex) + subcategoryIndex] = el;
}}
className={`fw-semibold text-white p-2 mb-2 text-truncate w-100 ${styles.title}`}
style={{ backgroundColor: bgListColor }}
>
{cat} / {subcat}
</div>
<div className="row g-4 mb-4">
{sortItems(cat, subcat).map((item: Item) => {
return (
<div key={`card_${item.id}`} className="col-12 col-lg-6 col-xxl-4 col-xxxl-3">
<div
className={`card rounded-0 p-3 ${styles.card}`}
onClick={() => updateActiveItemId(item.id)}
>
<Card item={item} className="h-100" />
</div>
</div>
);
})}
</div>
</div>
);
})}
</div>
);
})}
</>
);
};

export default Content;
Loading

0 comments on commit a94ee1e

Please sign in to comment.