Skip to content

Commit

Permalink
Merge branch 'feature/applications' of github.com:multiversx/mx-explo…
Browse files Browse the repository at this point in the history
…rer-dapp into feature/staking-v4
  • Loading branch information
radumojic committed Feb 21, 2024
2 parents adb61b7 + 13cb952 commit b715fdb
Show file tree
Hide file tree
Showing 16 changed files with 322 additions and 77 deletions.
11 changes: 11 additions & 0 deletions public/assets/img/default-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/appConstants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const ZERO = '0';
export const ELLIPSIS = '...';
export const PLACEHOLDER_IMAGE_PATH = 'assets/img/default.png';
export const SVG_PLACEHOLDER_IMAGE_PATH = 'assets/img/default.svg';
export const SVG_ICON_PLACEHOLDER_IMAGE_PATH = 'assets/img/default-icon.svg';

export const TRANSACTIONS_TABLE_FIELDS = [
'txHash',
Expand Down
11 changes: 11 additions & 0 deletions src/assets/img/default-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions src/components/Cards/ShowcaseCard/ShowcaseCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import classNames from 'classnames';

import { SVG_PLACEHOLDER_IMAGE_PATH } from 'appConstants';
import { SVG_ICON_PLACEHOLDER_IMAGE_PATH } from 'appConstants';
import { WithClassnameType } from 'types';

export interface ShowcaseCardUIType extends WithClassnameType {
Expand Down Expand Up @@ -47,14 +47,14 @@ export const ShowcaseCard = ({
})}
>
<img
src={icon ?? SVG_PLACEHOLDER_IMAGE_PATH}
src={icon ?? SVG_ICON_PLACEHOLDER_IMAGE_PATH}
alt=' '
className={classNames('icon-blur-bg img-fluid', {
default: !Boolean(icon)
})}
/>
<img
src={icon ?? SVG_PLACEHOLDER_IMAGE_PATH}
src={icon ?? SVG_ICON_PLACEHOLDER_IMAGE_PATH}
alt={`${detailsRank ? `#${detailsRank} ` : ''} Logo`}
className={classNames('icon img-fluid', { default: !Boolean(icon) })}
/>
Expand Down
133 changes: 86 additions & 47 deletions src/components/Cards/ShowcaseCard/showcaseCard.styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
background-color: rgba(var(--neutral-750-rgb), 0.5);
overflow: hidden;
position: relative;
scroll-snap-align: center;
scroll-margin-right: 3rem;

&-container {
scroll-snap-align: center;
scroll-margin-right: 3rem;
}

&-header {
display: flex;
Expand All @@ -39,9 +42,7 @@
margin-left: -4.75rem;
margin-top: -2.75rem;
pointer-events: none;
&.default {
margin-left: -5.25rem;
}

.icon-blur-bg,
.icon {
position: absolute;
Expand All @@ -50,10 +51,8 @@
top: 0;
bottom: 0;
margin: auto;
&:not(.default) {
border-radius: 50%;
overflow: hidden;
}
border-radius: 50%;
overflow: hidden;
}

.icon-blur-bg {
Expand All @@ -63,14 +62,13 @@
opacity: 0.25;
filter: blur(0.75rem);
mask: radial-gradient(circle, black 0%, transparent 70%);
&.default {
opacity: 0.8;
}
}
.icon {
width: 6.25rem;
min-width: 6.25rem;
&.default {
width: 5.25rem;
min-width: 5.25rem;
}
}
}
&-title {
Expand All @@ -85,44 +83,85 @@
position: relative;
margin-left: -0.75rem;
margin-right: -0.75rem;
&:before,
&:after {
content: ' ';
.showcase-card-scroll {
display: flex;
gap: 0.75rem;
overflow-x: auto;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
padding-left: 0.75rem;
padding-right: 4rem;
-ms-overflow-style: none;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}

.showcase-card-arrow {
position: absolute;
top: 0;
height: 100%;
width: 0.75rem;
bottom: 0;
display: flex;
z-index: 1;
}
&:before {
left: 0;
background: linear-gradient(
270deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 1) 50%
);
}
&:after {
right: 0;
width: 6rem;
background: linear-gradient(
90deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 1) 100%
);
opacity: 0;
align-items: center;
cursor: pointer;
pointer-events: none;

&:before {
content: '';
position: absolute;
height: 100%;
width: 6rem;
top: 0;
z-index: 0;
}

&.show {
pointer-events: all;
opacity: 1;
}

&.left {
left: 0;
&:before {
background: linear-gradient(
270deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 1) 100%
);
}
}

&.right {
right: 0;
justify-content: flex-end;
&:before {
right: 0;

background: linear-gradient(
90deg,
rgba(0, 0, 0, 0) 0%,
rgb(0, 0, 0) 100%
);
}
}

.showcase-card-arrow-icon {
color: var(--primary);
position: relative;
height: 2.5rem;
}
}
}
.showcase-card-scroll {
display: flex;
gap: 0.75rem;
overflow-x: auto;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
padding-left: 0.75rem;
padding-right: 4rem;
-ms-overflow-style: none;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;

// disable scroll snap on firefox

.firefox {
.showcase-card-container {
scroll-snap-type: unset;
scroll-snap-align: unset;
scroll-margin-right: unset;
}
}
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ export * from './useNetworkRoute';
export * from './useNetworkRouter';
export * from './useNotifications';
export * from './useScamFlag';
export * from './useScollInView';
export * from './useSearch';
export * from './useTempStorageNotification';
126 changes: 126 additions & 0 deletions src/hooks/useScollInView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { MouseEvent, useEffect, useMemo, useRef, useState } from 'react';

export const useScollInView = () => {
const [elementsIndexesInView, setElementsIndexesInView] = useState<number[]>(
[]
);

const scrollableElements = useRef<HTMLElement[]>([]);
const dispersionIndexes = scrollableElements.current.map((_, index) => index);

const shouldDisplayArrow = (index: number) =>
elementsIndexesInView.length > 0 && !elementsIndexesInView.includes(index);

const [firstElementIndex] = dispersionIndexes;
const [lastElementIndex] = dispersionIndexes.slice().reverse();

const showLeftInViewArrow = shouldDisplayArrow(firstElementIndex);
const showRightInViewArrow = shouldDisplayArrow(lastElementIndex);

const handleElementReference = (element: HTMLElement | null) => {
if (!element || scrollableElements.current.includes(element)) {
return;
}

scrollableElements.current.push(element);
};

const handleScrollIntoView = (elementIndex: number) => {
const elementToScrollToView = scrollableElements.current[elementIndex];
const scrollIntoViewOptions: ScrollIntoViewOptions = {
behavior: 'smooth',
inline: 'center',
block: 'nearest'
};

elementToScrollToView.scrollIntoView(scrollIntoViewOptions);
};

const handlePreviousArrowClick = (event: MouseEvent<HTMLElement>) => {
const previousElementIndex = Math.min(...elementsIndexesInView);
const previousElementExists = elementsIndexesInView.length > 1;
const processedIndex = previousElementExists
? previousElementIndex
: previousElementIndex - 1;

event.preventDefault();
event.stopPropagation();
handleScrollIntoView(processedIndex);
};

const handleNextArrowClick = (event: MouseEvent<HTMLElement>) => {
const nextElementIndex = Math.max(...elementsIndexesInView);
const nextElementExists = elementsIndexesInView.length > 1;
const processedIndex = nextElementExists
? nextElementIndex
: nextElementIndex + 1;

event.preventDefault();
event.stopPropagation();
handleScrollIntoView(processedIndex);
};

const processIndexFromEntry = (
currentInViewEntry: IntersectionObserverEntry
) => {
const currentElement = currentInViewEntry.target as HTMLElement;
const currentIndex = Number(currentElement.dataset.index);

return currentIndex;
};

const filterIntersections = (observerEntry: IntersectionObserverEntry) =>
observerEntry.isIntersecting;

const updateElementInViewStatus = (
observerEntries: IntersectionObserverEntry[]
) => {
setElementsIndexesInView((currentIndexesInView) => {
if (currentIndexesInView.length === 0) {
return observerEntries
.filter(filterIntersections)
.map(processIndexFromEntry);
}

const newOutViewIndexes = observerEntries
.filter((observerEntry) => !observerEntry.isIntersecting)
.map(processIndexFromEntry);

const newInViewIndexes = observerEntries
.filter(filterIntersections)
.map(processIndexFromEntry);

const cumulatedIndexes = currentIndexesInView.concat(newInViewIndexes);
const updatedElementInViewIndexes = cumulatedIndexes.filter(
(index) => !newOutViewIndexes.includes(index)
);

return updatedElementInViewIndexes;
});
};

const observer = useMemo(
() =>
new IntersectionObserver(updateElementInViewStatus, {
threshold: 1,
rootMargin: '100% 0% 100% 0%'
}),
[scrollableElements]
);

useEffect(() => {
scrollableElements.current.forEach((scrollableElement) => {
observer.observe(scrollableElement);
});

return () => observer.disconnect();
}, []);

return {
handleElementReference,
handleNextArrowClick,
handlePreviousArrowClick,
showLeftInViewArrow,
showRightInViewArrow
};
};
2 changes: 1 addition & 1 deletion src/pages/Analytics/Analytics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export const Analytics = () => {

<ChartWrapper>
<div className='px-3 pb-3'>
<ChartContractsTransactions />
<ChartContractsTransactions isStandalone />
</div>
</ChartWrapper>
<ChartWrapper size='half'>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Applications/Applications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useSelector } from 'react-redux';
import { useSearchParams } from 'react-router-dom';

import { ELLIPSIS } from 'appConstants';
import { ReactComponent as DefaultImage } from 'assets/img/default.svg';
import { ReactComponent as DefaultImage } from 'assets/img/default-icon.svg';
import {
Loader,
Pager,
Expand Down Expand Up @@ -152,7 +152,7 @@ export const Applications = () => {
/>
) : (
<div className='side-icon side-icon-md-large d-flex align-items-center justify-content-center'>
<DefaultImage className='p-2' />
<DefaultImage />
</div>
)}
<AccountName
Expand Down
Loading

0 comments on commit b715fdb

Please sign in to comment.