Skip to content

Commit

Permalink
Merge pull request #21 from terra-money/new/ui-updates
Browse files Browse the repository at this point in the history
New/UI updates
  • Loading branch information
JoshuaBrigati authored Dec 11, 2023
2 parents 8976c4a + bc1e7a4 commit f40e279
Show file tree
Hide file tree
Showing 36 changed files with 1,668 additions and 156 deletions.
5 changes: 5 additions & 0 deletions frontend/src/assets/CircleClear.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions frontend/src/assets/DropdownArrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions frontend/src/assets/ExternalLink.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions frontend/src/assets/Filter.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions frontend/src/assets/Search.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions frontend/src/assets/socials/Medium.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions frontend/src/assets/socials/Telegram.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions frontend/src/assets/socials/Twitter.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 58 additions & 0 deletions frontend/src/components/checkbox/checkbox.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// @import 'scss/font_mixins';

.checkbox {
display: inline-flex;
justify-content: center;
align-items: center;

cursor: pointer;
gap: 8px;
user-select: none;

&.checked .indicator {
opacity: 1;
}

&.disabled {
cursor: not-allowed;
opacity: 0.5;
}

.text {
flex: 1;
// @include Small;
color: var(--token-dark-500);
}

&.checked {
.track {
border: solid 1px var(--token-primary-400);
}

.text {
color: var(--token-light-white);
transition: color 100ms;
}
}
}

.track {
display: flex;
justify-content: center;
align-items: center;

border: solid 1px var(--token-dark-500);
border-radius: 6px;
width: 18px;
height: 18px;
}

.indicator {
background: var(--token-primary-500);
border-radius: 2px;
width: 8px;
height: 8px;

opacity: 0;
transition: opacity 100ms;
}
30 changes: 30 additions & 0 deletions frontend/src/components/checkbox/checkbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ForwardedRef, forwardRef, InputHTMLAttributes } from 'react';
import classNames from 'classnames/bind';
import styles from './checkbox.module.scss';

const cx = classNames.bind(styles);

export interface CheckboxProps extends InputHTMLAttributes<HTMLInputElement> {
label: string
checked?: boolean
}

const Checkbox = forwardRef(
(
{ className, label, checked, ...attrs }: CheckboxProps,
ref: ForwardedRef<HTMLInputElement>
) => {
const { disabled } = attrs;
return (
<label className={cx(styles.checkbox, { checked, disabled }, className)}>
<input {...attrs} type='checkbox' hidden ref={ref} />
<span className={styles.track}>
<span className={styles.indicator} />
</span>
<span className={styles.text}>{label}</span>
</label>
);
},
);

export default Checkbox;
123 changes: 123 additions & 0 deletions frontend/src/components/filters/dropdowns/FilterDropdown.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
.filter__row {
display: flex;
gap: 24px;
align-items: center;
margin-bottom: 24px;
}

.filter__dropdown__container {
max-width: 200px;
width: 100%;
display: flex;
gap: 24px;
position: relative;

.selector__wrapper {
display: flex;
align-items: center;
gap: 4px;
width: 100%;

.selector {
padding: 8px 12px;
background: var(--token-light-500);
border: 1px solid var(--token-light-800);
border-radius: 8px;
overflow: hidden;
display: flex;
justify-content: space-between;
align-items: center;
gap: 8px;
appearance: none;
width: 100%;

.selected__wrapper {
display: flex;
align-items: center;
gap: 8px;
}

span {
display: flex;
font-size: 14px;
font-weight: 500;
color: var(--token-dark-500);
}

&.open {
background-color: var(--token-light-800);
border-color: var(--token-dark-700);
}

&:hover {
background-color: var(--token-light-800);
border-color: var(--token-dark-700);
transition: all .25s;
}
}

.clear__wrapper {
display: flex;
align-items: center;
}
}

.options {
padding: 8px 2px 8px 12px;
position: absolute;
width: 100%;
background: var(--token-light-800);
border: 1px solid var(--token-dark-700);

border-radius: 8px;
z-index: 10;
max-height: 200px;
box-shadow: 0px 5px 7px 0px #0000009c;
top: 40px;
overflow: hidden;

.options__container {
padding-right: 10px;
padding-bottom: 8px;
overflow: auto;
max-height: 190px;
display: flex;
flex-direction: column;
gap: 4px;

&::-webkit-scrollbar {
width: 12px;
display: block;
}

&::-webkit-scrollbar-thumb {
border-radius: 16px;
background-color: hsl(0, 0%, 47%);
border: 2px solid var(--token-light-800);
}

&::-webkit-scrollbar-track {
background-color: transparent;
}
}
}
}

@media (max-width: 590px) {
.filter__row {
// flex-direction: column;
flex-wrap: wrap;
align-items: flex-start;
gap: 4px;
}

.filter__dropdown__container {
.selector__wrapper {
.selector {
span {
font-size: 12px;
}
}
}
}
}
119 changes: 119 additions & 0 deletions frontend/src/components/filters/dropdowns/InhabitantFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { useEffect, useRef, useState } from 'react';
import classNames from 'classnames/bind';
import { inhabitantOptions } from '../options';
import { GalleryFiltersProps } from 'pages/nft/NFTs';
import { ReactComponent as DropdownArrowIcon } from "assets/DropdownArrow.svg";
import { ReactComponent as CircleClearIcon } from "assets/CircleClear.svg";
import Checkbox from 'components/checkbox/checkbox';
import styles from './FilterDropdown.module.scss';

const cx = classNames.bind(styles);

export const InhabitantFilter = ({
galleryFilters,
setGalleryFilters,
}: {
galleryFilters: GalleryFiltersProps
setGalleryFilters: ({
planetNumber,
planetNames,
planetInhabitants,
nftObjects
}: GalleryFiltersProps) => void,
}) => {
const [open, setOpen] = useState(false)
const ref = useRef<HTMLDivElement>(null)

useEffect(() => {
document.addEventListener("mousedown", handleClickOutside)
return () => {
document.removeEventListener("mousedown", handleClickOutside)
}
}, [])

const handleClickOutside = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
setOpen(false)
}
}

const [selectedInhabitants, setSelectedInhabitants] = useState<string[]>(galleryFilters.planetInhabitants || []);
const inhabitantDropdownValue =
selectedInhabitants.length ?
selectedInhabitants.length === 1 ?
selectedInhabitants[0] : `${selectedInhabitants.length} inhabitant selected`
: "Select an inhabitant";

useEffect(() => {
setGalleryFilters({
...galleryFilters,
planetInhabitants: selectedInhabitants,
});
}, [selectedInhabitants]);

const handleInhabitantClick = (inhabitantsName: string) => {
if (selectedInhabitants?.includes(inhabitantsName)) {
setSelectedInhabitants(selectedInhabitants.filter(name => name !== inhabitantsName));
} else {
setSelectedInhabitants(selectedInhabitants ? [...selectedInhabitants, inhabitantsName] : [inhabitantsName]);
}
}

const clearInhabitantFilters = () => {
setGalleryFilters({
...galleryFilters,
planetInhabitants: [],
});
setSelectedInhabitants([]);
}

return (
<div className={styles.filter__dropdown__container} ref={ref}>
<div className={styles.selector__wrapper}>
<button
type="button"
className={cx(styles.selector, { open })}
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
setOpen((o) => !o)
}}
>
<span className={styles.selected__wrapper}>
<span>{inhabitantDropdownValue}</span>
</span>
<DropdownArrowIcon className={styles.caret} fill="var(--token-dark-500)" />
</button>
{selectedInhabitants.length > 0 && (
<div className={styles.clear__wrapper}>
<button
className={styles.clear}
onClick={clearInhabitantFilters}
>
<CircleClearIcon
fill={"transparent"}
stroke={"var(--token-dark-500)"}
width={18}
height={18}
/>
</button>
</div>
)}
</div>
{open && (
<div className={cx(styles.options)}>
<div className={cx(styles.options__container)}>
{inhabitantOptions.map(inhabitant => (
<Checkbox
key={inhabitant}
label={inhabitant}
checked={selectedInhabitants?.includes(inhabitant)}
onClick={() => handleInhabitantClick(inhabitant)}
/>
))}
</div>
</div>
)}
</div>
)
}
Loading

0 comments on commit f40e279

Please sign in to comment.