Skip to content

Commit

Permalink
Merge pull request #57 from CudoVentures/cudos-dev
Browse files Browse the repository at this point in the history
Cudos dev
  • Loading branch information
mlukanova authored Jun 20, 2023
2 parents dde57b5 + afef9dc commit 444a1bb
Show file tree
Hide file tree
Showing 21 changed files with 308 additions and 118 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import { Box, Dialog as MuiDialog, Typography } from '@mui/material'
import { useSelector } from 'react-redux'
import { Oval as OvalLoader } from 'svg-loaders-react'
import ClipLoader from "react-spinners/ClipLoader";

import { RootState } from '../../../../../store'
import { COLORS } from '../../../../../../core/theme/colors'
Expand All @@ -24,7 +24,7 @@ const Loading = () => {
}}>
{message ?
<Box gap={2} sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
{loadingSpinner ? <OvalLoader style={{ width: '60px', height: '60px', stroke: COLORS.LIGHT_BLUE[90] }} /> : null}
{loadingSpinner ? <ClipLoader color={COLORS.LIGHT_BLUE[90]} cssOverride={{ width: '60px', height: '60px' }} /> : null}
<Typography variant='h5'>{message}</Typography>
</Box>
: null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Box, Tooltip, Typography, Dialog as MuiDialog, MenuItem, Select } from
import { LoadingButton } from '@mui/lab'
import { ThreeDots as ThreeDotsLoading } from 'svg-loaders-react'
import { useDispatch, useSelector } from 'react-redux'
import { Oval as OvalLoader } from 'svg-loaders-react'
import ClipLoader from "react-spinners/ClipLoader";

import {
detectUserBrowser,
Expand Down Expand Up @@ -256,7 +256,7 @@ const WalletSelector = () => {
</Typography>
{selectChainId ?
<Box gap={3} style={styles.btnsHolder}>
{loadSelectChainId ? <OvalLoader style={styles.ovalLoader} /> :
{loadSelectChainId ? <ClipLoader color={COLORS.LIGHT_BLUE[90]} cssOverride={styles.ovalLoader} /> :
<Fragment>
<Select
disableUnderline
Expand Down Expand Up @@ -337,7 +337,7 @@ const WalletSelector = () => {
</Box>
:
<Box gap={3} style={styles.btnsHolder}>
{loadSelectChainId ? <OvalLoader style={styles.ovalLoader} /> :
{loadSelectChainId ? <ClipLoader color={COLORS.LIGHT_BLUE[90]} cssOverride={styles.ovalLoader} /> :
<Fragment>
{getSupportedWallets().map((wallet, idx) => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export const styles = {
width: '50px',
height: '50px',
margin: '37px 0px',
stroke: COLORS.LIGHT_BLUE[90]
},
pluginWarning: {
maxWidth: '550px',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import React, { CSSProperties } from 'react';
import SVG from 'react-inlinesvg';
import moment from "moment";
import { Box, Divider } from '@mui/material';
import { JdenticonConfig, toSvg } from 'jdenticon';
import { Oval as OvalLoader } from 'svg-loaders-react'
import ClipLoader from "react-spinners/ClipLoader";

import { APP_DETAILS } from '../../../utilities/Constants';
import { COLORS } from '../../../theme/colors';
Expand Down Expand Up @@ -282,6 +282,8 @@ export const SVG_FRAMES = {
frame1674: frame1674
}


export const StyledPuffLoader = () => {
return <OvalLoader style={generalStyles.spinner} />
const override: CSSProperties = generalStyles.spinner;
return <ClipLoader color={COLORS.LIGHT_BLUE[90]} cssOverride={override} />
}
81 changes: 48 additions & 33 deletions apps/frontend/src/core/presentation/components/SearchBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { Fragment, useEffect, useRef, useState } from "react"
import { useDispatch, useSelector } from "react-redux"
import { Box, Divider, Fade, Input, MenuItem, Select, Tooltip, Typography } from "@mui/material"
import { Box, Divider, Fade, Input, MenuItem, Select, SelectChangeEvent, Tooltip, Typography } from "@mui/material"
import { CancelRounded } from '@mui/icons-material'
import { getCosmosNetworkPrettyName } from "cudosjs"

Expand All @@ -17,21 +17,32 @@ const SearchBar = ({ networks, displayDataLength }: { networks: string[], displa

const dispatch = useDispatch()
const searchBar = useRef<HTMLInputElement>()
const chainSelector = useRef<HTMLInputElement>()
const chainSelector = useRef<HTMLDivElement>()
const hide = useRef<HTMLDivElement>()
const { searchTerms, appliedFilter, ascendingOrder, chainFilter, activeSearch } = useSelector((state: RootState) => state.searchState)
const [filterOpen, setFilterOpen] = useState<boolean>(false)
const [displaySortingIcon, setDisplaySortingIcon] = useState<boolean>(true)
const [dropDownOpen, setDropDownOpen] = useState<boolean>(false)
const [expandChainSelector, setExpandChainSelector] = useState<boolean>(false)
const [showChainSelectorCloseIcon, setChainSelectorCloseIcon] = useState<boolean>(false)
const [chainSelectorPlaceholder, setChainSelectorPlaceholder] = useState<string>('')
const [chainSelectorOpen, setChainSelectorOpen] = useState<boolean>(false)

const [showSearchBarCloseIcon, setShowSearchBarCloseIcon] = useState<boolean>(false)
const [expandSearchBar, setExpandSearchBar] = useState<boolean>(false)
const [searchBarPlaceholder, setSearchBarPlaceholder] = useState<string>('')

const invalidSearch = expandSearchBar && !displayDataLength && !!searchTerms

const estimateStringWidth = (string: string, fontSize: string) => {
const element = document.createElement('span');
element.innerHTML = string;
element.style.fontSize = fontSize;
document.body.appendChild(element);
const width = element.getBoundingClientRect().width;
document.body.removeChild(element);
return width;
}

const hasScrollbar = () => {
return document.documentElement.scrollHeight > document.documentElement.clientHeight;
};
Expand All @@ -58,30 +69,42 @@ const SearchBar = ({ networks, displayDataLength }: { networks: string[], displa
}

//CHAIN SELECTOR
const handleChainSelectorTransitionEnd = () => {
if (expandChainSelector) {
chainSelector.current?.click()
setChainSelectorCloseIcon(true)
setChainSelectorPlaceholder('Select Network')
const handleNetworkFilterChange = (e: SelectChangeEvent<string>, child: React.ReactNode) => {
if (hide.current) {
hide.current.style.opacity = '0'
}
}
const width = estimateStringWidth(e.target.value, '16px');
dispatch(updateSearchState({ chainFilter: e.target.value }));
setTimeout(() => {
chainSelector.current.style.width = `${width + 80}px`;

const handleExpandChainSelector = () => {
setExpandChainSelector(true)
}, 200);
setTimeout(() => {
hide.current.style.opacity = '1'
}, 600)
}

const handleShrinkChainSelector = () => {
if (expandChainSelector) {
setExpandChainSelector(false)
setChainSelectorCloseIcon(false)
const handleExpandChainSelector = () => {
if (!chainSelectorOpen) {
chainSelector.current.style.width = '195px'
setTimeout(() => {
dispatch(updateSearchState({
chainFilter: ''
}))
setChainSelectorCloseIcon(true)
setChainSelectorPlaceholder('Select Network')
setChainSelectorOpen(true)
}, 300)
}
}

const handleShrinkChainSelector = () => {
dispatch(updateSearchState({ chainFilter: '' }))
setChainSelectorPlaceholder('')
setChainSelectorCloseIcon(false)
setChainSelectorOpen(false)
setTimeout(() => {
chainSelector.current.style.width = '48px'
}, 100)
}

//SEARCH BAR
const handleSearchBarTransitionEnd = () => {
if (expandSearchBar) {
Expand Down Expand Up @@ -117,15 +140,6 @@ const SearchBar = ({ networks, displayDataLength }: { networks: string[], displa
//eslint-disable-next-line
}, [showSearchBarCloseIcon])

useEffect(() => {
if (!showChainSelectorCloseIcon) {
setChainSelectorPlaceholder('')
handleShrinkChainSelector()
}

//eslint-disable-next-line
}, [showChainSelectorCloseIcon])

return (
<Box sx={{ gap: '12px', display: 'flex', alignItems: 'center' }}>
<Tooltip
Expand Down Expand Up @@ -166,21 +180,22 @@ const SearchBar = ({ networks, displayDataLength }: { networks: string[], displa
</Box>
</Tooltip>
<Box
onTransitionEnd={handleChainSelectorTransitionEnd}
ref={chainSelector}
onClick={handleExpandChainSelector}
gap={'10px'}
display={'flex'}
alignItems={'center'}
style={{ pointerEvents: invalidSearch ? 'none' : 'auto' }}
sx={styles.searchBar(expandChainSelector, false, "195px")}
sx={styles.chainSelector}
>
<Box sx={{ display: 'flex', marginLeft: '-9px' }}>
<Box onClick={chainSelectorOpen ? () => setDropDownOpen(true) : null} sx={{ display: 'flex', marginLeft: '-9px' }}>
<SvgComponent
type={LAYOUT_CONTENT_TEXT.GlobusIcon}
style={{ color: invalidSearch ? '#88898c' : COLORS.STEEL_GRAY[20] }}
/>
</Box>
<Select
ref={hide}
disabled={invalidSearch || !networks.length}
MenuProps={styles.chainSelectorDropoDownMenuProps}
disableUnderline
Expand All @@ -201,10 +216,10 @@ const SearchBar = ({ networks, displayDataLength }: { networks: string[], displa
}
sx={styles.chainSelectorDropDown}
value={chainFilter}
onChange={(e) => dispatch(updateSearchState({ chainFilter: e.target.value }))}
onChange={handleNetworkFilterChange}
IconComponent={() => null}
endAdornment={showChainSelectorCloseIcon ?
<Box marginLeft={'-24px'} onClick={() => setChainSelectorCloseIcon(false)}>
endAdornment={showChainSelectorCloseIcon && chainSelectorOpen ?
<Box marginLeft={'-24px'} onClick={handleShrinkChainSelector}>
<CancelRounded sx={{ ...styles.cancelIcon, color: invalidSearch ? '#88898c' : COLORS.STEEL_GRAY[40] }} />
</Box>
: null}
Expand Down
14 changes: 11 additions & 3 deletions apps/frontend/src/core/presentation/components/SearchBar/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,19 @@ export const styles = {
padding: '15px 24px 15px 20px',
height: '48px',
border: noResult ? `1px solid ${COLORS.RED[60]}` : `1px solid ${COLORS.STEEL_GRAY[70]}`,
borderRadius: '64px'
borderRadius: '64px',
}
},
chainSelector: {
width: '48px',
cursor: 'pointer',
transition: 'width .4s ease-in-out',
padding: '15px 24px 15px 20px',
height: '48px',
border: `1px solid ${COLORS.STEEL_GRAY[70]}`,
borderRadius: '64px',

},
menuItem: {
height: '48px',
borderRadius: '10px',
Expand Down Expand Up @@ -64,8 +74,6 @@ export const styles = {
background: COLORS.STEEL_GRAY[100],
borderRadius: '8px',
marginLeft: '-18px',
minWidth: '195px',
maxWidth: '195px'
},
},
},
Expand Down
121 changes: 119 additions & 2 deletions apps/frontend/src/core/utilities/ProjectUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ export const handleLinkOut = (url: string) => {
}
}

export const setBlobToB64Img = async (imgData: Blob, setter: React.Dispatch<React.SetStateAction<string>>) => {
const b64ImgString = await blobToBase64(imgData)
export const setBlobToB64Img = async (imgData: Blob, setter: React.Dispatch<React.SetStateAction<string>>, thumbnail?: { MAX_WIDTH: number, MAX_HEIGHT: number }) => {
const b64ImgString = await blobToBase64(imgData) as string
if (thumbnail) {
createThumbnail(b64ImgString, thumbnail, setter);
return
}
setter(b64ImgString as string)
}

Expand Down Expand Up @@ -72,3 +76,116 @@ export const formatAddress = (text: string, sliceIndex: number): string => {
}
return `${text.slice(0, sliceIndex)}...${text.slice(len - 4, len)}`
}

const applySharpeningFilter = (
r: number,
g: number,
b: number,
alpha: number,
neighborPixels: [number, number, number, number][]
) => {
const kernel = [
[-0.1, -0.1, -0.1],
[-0.1, 1.8, -0.1],
[-0.1, -0.1, -0.1],
];

let rSharp = 0;
let gSharp = 0;
let bSharp = 0;

for (let i = 0; i < neighborPixels.length; i++) {
const [rNeighbor, gNeighbor, bNeighbor, alphaNeighbor] = neighborPixels[i];
const weight = kernel[Math.floor(i / 3)][i % 3];

rSharp += rNeighbor * weight;
gSharp += gNeighbor * weight;
bSharp += bNeighbor * weight;
}

rSharp = Math.max(0, Math.min(255, rSharp));
gSharp = Math.max(0, Math.min(255, gSharp));
bSharp = Math.max(0, Math.min(255, bSharp));

return [rSharp, gSharp, bSharp];
};

const getNeighborPixels = (data: Uint8ClampedArray, width: number, height: number, row: number, col: number) => {
const pixels: [number, number, number, number][] = [];

for (let i = row - 1; i <= row + 1; i++) {
for (let j = col - 1; j <= col + 1; j++) {
if (i >= 0 && i < height && j >= 0 && j < width) {
const pixelIndex = (i * width + j) * 4;
pixels.push([data[pixelIndex], data[pixelIndex + 1], data[pixelIndex + 2], data[pixelIndex + 3]]);
}
}
}

return pixels;
};

const sharpenImage = (imageData: ImageData) => {
const { data, width, height } = imageData;
const filteredData = new Uint8ClampedArray(data.length);

for (let i = 0; i < height; i++) {
for (let j = 0; j < width; j++) {
const pixelIndex = (i * width + j) * 4;
const r = data[pixelIndex];
const g = data[pixelIndex + 1];
const b = data[pixelIndex + 2];

const alpha = data[pixelIndex + 3];
const neighborPixels = getNeighborPixels(data, width, height, i, j);

const [rSharp, gSharp, bSharp] = applySharpeningFilter(r, g, b, alpha, neighborPixels);
filteredData[pixelIndex] = rSharp;
filteredData[pixelIndex + 1] = gSharp;
filteredData[pixelIndex + 2] = bSharp;
filteredData[pixelIndex + 3] = alpha;
}
}

return new ImageData(filteredData, width, height);
};

export const createThumbnail = (originalImg: string, target: { MAX_WIDTH: number, MAX_HEIGHT: number }, callback: React.Dispatch<React.SetStateAction<string>>) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

const { MAX_WIDTH, MAX_HEIGHT } = target;

const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = function () {
let width = img.width;
let height = img.height;

const aspectRatio = width / height;
const targetWidth = Math.min(MAX_WIDTH, width);
const targetHeight = Math.min(MAX_HEIGHT, height);

if (width > targetWidth || height > targetHeight) {
if (aspectRatio > 1) {
width = targetWidth;
height = width / aspectRatio;
} else {
height = targetHeight;
width = height * aspectRatio;
}
}

canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);

const imageData = ctx.getImageData(0, 0, width, height);
const filteredData = sharpenImage(imageData);
ctx.putImageData(filteredData, 0, 0);

const dataUrl = canvas.toDataURL('image/png');
callback(dataUrl);
};
img.src = originalImg;
};
Loading

0 comments on commit 444a1bb

Please sign in to comment.