Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/token pair image #159

Merged
merged 9 commits into from
Jun 17, 2021
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from "react";
import { renderWithTheme, setupMockIntersectionObserver } from "../../testHelpers";
import TokenImage from "../../components/Image/TokenImage";

it("renders correctly", () => {
setupMockIntersectionObserver();
const { asFragment } = renderWithTheme(
<TokenImage tokenAddress="0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82" height={48} width={48} />
);
expect(asFragment()).toMatchInlineSnapshot(`
<DocumentFragment>
.c0 {
-webkit-align-self: start;
-ms-flex-item-align: start;
align-self: start;
max-height: 48px;
max-width: 48px;
position: relative;
width: 100%;
}

.c0:after {
content: "";
display: block;
padding-top: 100%;
}

.c2 {
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}

.c1:before {
border-radius: 50%;
border: 1px solid rgba(0,0,0,0.25);
content: "";
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
z-index: 7;
}

<div
class="c0 c1"
>
<div
class="c2"
/>
</div>
</DocumentFragment>
`);
});
42 changes: 27 additions & 15 deletions packages/pancake-uikit/src/components/Image/BackgroundImage.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,42 @@
import React, { useEffect, useRef } from "react";
import styled from "styled-components";
import observerOptions from "./options";
import Wrapper from "./Wrapper";
import { ImageProps } from "./types";

const BackgroundImage: React.FC<ImageProps> = ({ src, ...otherProps }) => {
const imgRef = useRef(null);
const StyledBackgroundImage = styled(Wrapper)`
background-repeat: no-repeat;
background-size: contain;
`;

const BackgroundImage: React.FC<ImageProps> = ({ src, width, height, ...props }) => {
const ref = useRef<HTMLDivElement>(null);

useEffect(() => {
const img = imgRef.current as unknown as HTMLElement;
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
const { isIntersecting } = entry;
if (isIntersecting) {
img.style.backgroundImage = `url("${src}")`;
observer.disconnect();
}
});
}, observerOptions);
observer.observe(img);
let observer: IntersectionObserver;

if (ref.current) {
const div = ref.current;

observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
const { isIntersecting } = entry;
if (isIntersecting) {
div.style.backgroundImage = `url("${src}")`;
observer.disconnect();
}
});
}, observerOptions);
observer.observe(div);
}
return () => {
observer.disconnect();
if (observer) {
observer.disconnect();
}
};
}, [src]);

return <Wrapper ref={imgRef} {...otherProps} />;
return <StyledBackgroundImage ref={ref} width={width} height={height} {...props} />;
};

export default BackgroundImage;
44 changes: 24 additions & 20 deletions packages/pancake-uikit/src/components/Image/Image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,50 @@ import Wrapper from "./Wrapper";
import { ImageProps } from "./types";

const StyledImage = styled.img`
height: 100%;
left: 0;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
max-width: 100%;
`;

const Placeholder = styled.div`
height: 100%;
left: 0;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
`;

const Image: React.FC<ImageProps> = ({ src, alt, ...otherProps }) => {
const imgRef = useRef(null);
const Image: React.FC<ImageProps> = ({ src, alt, width, height, ...props }) => {
const imgRef = useRef<HTMLDivElement>(null);
const [isLoaded, setIsLoaded] = useState(false);

useEffect(() => {
const img = imgRef.current as unknown as HTMLImageElement;
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
const { isIntersecting } = entry;
if (isIntersecting) {
setIsLoaded(true);
observer.disconnect();
}
});
}, observerOptions);
observer.observe(img);
let observer: IntersectionObserver;

if (imgRef.current) {
observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
const { isIntersecting } = entry;
if (isIntersecting) {
setIsLoaded(true);
observer.disconnect();
}
});
}, observerOptions);
observer.observe(imgRef.current);
}

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

return (
<Wrapper ref={imgRef} {...otherProps}>
<Wrapper ref={imgRef} height={height} width={width} {...props}>
{isLoaded ? <StyledImage src={src} alt={alt} /> : <Placeholder />}
</Wrapper>
);
Expand Down
29 changes: 29 additions & 0 deletions packages/pancake-uikit/src/components/Image/TokenImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import styled from "styled-components";
import { TokenImageProps } from "./types";
import Image from "./Image";

const StyledTokenImage = styled(Image)`
&:before {
border-radius: 50%;
border: 1px solid rgba(0, 0, 0, 0.25);
content: "";
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
z-index: 7;
}
`;

const TokenImage: React.FC<TokenImageProps> = ({
tokenAddress,
baseUrl = "/images/tokens",
imageFormat = "svg",
...props
}) => {
return <StyledTokenImage src={`${baseUrl}/${tokenAddress}.${imageFormat}`} {...props} />;
};

export default TokenImage;
38 changes: 38 additions & 0 deletions packages/pancake-uikit/src/components/Image/TokenPairImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from "react";
import { TokenPairImageProps, variants } from "./types";
import { StyledPrimaryImage, StyledSecondaryImage } from "./styles";
import Wrapper from "./Wrapper";

const TokenPairImage: React.FC<TokenPairImageProps> = ({
secondaryTokenAddress,
primaryTokenAddress,
width,
height,
variant = variants.DEFAULT,
primaryImageProps = {},
secondaryImageProps = {},
...props
}) => {
const secondaryImageSize = Math.floor(width / 2);

return (
<Wrapper position="relative" width={width} height={height} {...props}>
<StyledPrimaryImage
variant={variant}
tokenAddress={primaryTokenAddress}
width={width}
height={height}
{...primaryImageProps}
/>
<StyledSecondaryImage
variant={variant}
tokenAddress={secondaryTokenAddress}
width={secondaryImageSize}
height={secondaryImageSize}
{...secondaryImageProps}
/>
</Wrapper>
);
};

export default TokenPairImage;
26 changes: 17 additions & 9 deletions packages/pancake-uikit/src/components/Image/Wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
import React, { forwardRef } from "react";
import styled from "styled-components";
import { space } from "styled-system";
import { ContainerProps } from "./types";
import { WrapperProps } from "./types";

const Wrapper = styled.div<ContainerProps>`
const StyledWrapper = styled.div<{ $width: number; $height: number }>`
align-self: start;
max-height: ${({ $height }) => $height}px;
max-width: ${({ $width }) => $width}px;
position: relative;
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
height: ${({ height, responsive }) => (responsive ? 0 : height)}px;
max-width: ${({ width }) => width}px;
max-height: ${({ height }) => height}px;
width: 100%;
padding-top: ${({ width, height, responsive }) => (responsive ? (height / width) * 100 : 0)}%;

&:after {
content: "";
display: block;
padding-top: ${({ $width, $height }) => ($height / $width) * 100}%;
}

${space}
`;

const Wrapper = forwardRef<HTMLDivElement, WrapperProps>(({ width, height, ...props }, ref) => {
return <StyledWrapper ref={ref} $width={width} $height={height} {...props} />;
});

export default Wrapper;
Loading