added responsive features
This commit is contained in:
		@@ -30,7 +30,7 @@ interface BorderProps {
 | 
			
		||||
    isBottom?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ANNOUNCEMENT_BANNER_HEIGHT = '12rem';
 | 
			
		||||
export const ANNOUNCEMENT_BANNER_HEIGHT = '14rem';
 | 
			
		||||
 | 
			
		||||
export const AnnouncementBanner: React.StatelessComponent<Props> = (props: Props) => {
 | 
			
		||||
    const { heading, subline, mainCta, secondaryCta } = props;
 | 
			
		||||
@@ -43,9 +43,9 @@ export const AnnouncementBanner: React.StatelessComponent<Props> = (props: Props
 | 
			
		||||
                    <CustomHeading>{heading}</CustomHeading>
 | 
			
		||||
 | 
			
		||||
                    {subline && (
 | 
			
		||||
                        <Paragraph color={colors.white} isMuted={0.5} isNoMargin={true}>
 | 
			
		||||
                        <CustomParagraph color={colors.white} isMuted={0.5} isNoMargin={true}>
 | 
			
		||||
                            {subline}
 | 
			
		||||
                        </Paragraph>
 | 
			
		||||
                        </CustomParagraph>
 | 
			
		||||
                    )}
 | 
			
		||||
                </Column>
 | 
			
		||||
                <ColumnCta>
 | 
			
		||||
@@ -72,6 +72,7 @@ export const AnnouncementBanner: React.StatelessComponent<Props> = (props: Props
 | 
			
		||||
                        )}
 | 
			
		||||
 | 
			
		||||
                        {secondaryCta && (
 | 
			
		||||
                            <SecondaryButtonWrapper>
 | 
			
		||||
                                <Button
 | 
			
		||||
                                    color={colors.white}
 | 
			
		||||
                                    href={secondaryCta.href}
 | 
			
		||||
@@ -81,6 +82,7 @@ export const AnnouncementBanner: React.StatelessComponent<Props> = (props: Props
 | 
			
		||||
                                >
 | 
			
		||||
                                    {secondaryCta.text}
 | 
			
		||||
                                </Button>
 | 
			
		||||
                            </SecondaryButtonWrapper>
 | 
			
		||||
                        )}
 | 
			
		||||
                    </ButtonWrap>
 | 
			
		||||
                </ColumnCta>
 | 
			
		||||
@@ -93,6 +95,13 @@ interface CustomSectionProps extends SectionProps {
 | 
			
		||||
    dismissed: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const SecondaryButtonWrapper = styled.div`
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    @media (max-width: 56rem) {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
const BannerContentWrapper = styled.div`
 | 
			
		||||
    max-width: 1200px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
@@ -101,6 +110,15 @@ const BannerContentWrapper = styled.div`
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: space-between;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    @media (max-width: 56rem) {
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
const CustomParagraph = styled(Paragraph)`
 | 
			
		||||
    @media (max-width: 56rem) {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
const CustomSection = styled(Section)<CustomSectionProps>`
 | 
			
		||||
@@ -151,22 +169,22 @@ const CustomHeading = styled.h2`
 | 
			
		||||
 | 
			
		||||
const ButtonWrap = styled.div`
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
 | 
			
		||||
    @media (min-width: 768px) {
 | 
			
		||||
        * + * {
 | 
			
		||||
            margin-left: 15px;
 | 
			
		||||
    & > button,
 | 
			
		||||
    a {
 | 
			
		||||
        margin: 0 12px;
 | 
			
		||||
    }
 | 
			
		||||
    & *:first-child {
 | 
			
		||||
        margin-left: 0;
 | 
			
		||||
    }
 | 
			
		||||
    & *:last-child {
 | 
			
		||||
        margin-right: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @media (max-width: 768px) {
 | 
			
		||||
        a,
 | 
			
		||||
        button {
 | 
			
		||||
            display: block;
 | 
			
		||||
            width: 220px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        * + * {
 | 
			
		||||
            margin-top: 15px;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column-reverse;
 | 
			
		||||
        & > button,
 | 
			
		||||
        a {
 | 
			
		||||
            margin: 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
@@ -185,7 +203,8 @@ const Border = styled.div<BorderProps>`
 | 
			
		||||
    top: ${props => !props.isBottom && 0};
 | 
			
		||||
    bottom: ${props => props.isBottom && 0};
 | 
			
		||||
    transform: translate(-112px);
 | 
			
		||||
 | 
			
		||||
    z-index: 0;
 | 
			
		||||
    pointer-events: none;
 | 
			
		||||
    @media (max-width: 768px) {
 | 
			
		||||
        width: calc(100% + 82px);
 | 
			
		||||
        height: 40px;
 | 
			
		||||
 
 | 
			
		||||
@@ -93,7 +93,7 @@ const SectionBase = styled.section<SectionProps>`
 | 
			
		||||
    width: ${props => !props.isFullWidth && 'calc(100% - 60px)'};
 | 
			
		||||
    max-width: 1500px;
 | 
			
		||||
    margin: 0 auto;
 | 
			
		||||
    padding: ${props => (!!props.padding && props.padding) || (props.isPadded && '120px 0')};
 | 
			
		||||
    padding: ${props => props.isPadded && '120px 0'};
 | 
			
		||||
    background-color: ${props => props.theme[`${props.bgColor}BgColor`] || props.bgColor};
 | 
			
		||||
    position: relative;
 | 
			
		||||
    overflow: ${props => !props.isFullWidth && 'hidden'};
 | 
			
		||||
 
 | 
			
		||||
@@ -56,8 +56,4 @@ const InputWrapper = styled.div<InputProps>`
 | 
			
		||||
    position: relative;
 | 
			
		||||
    width: ${props => props.width || '100%'};
 | 
			
		||||
    border-bottom: 1px solid #d5d5d5;
 | 
			
		||||
    @media (max-width: 768px) {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        margin-bottom: 30px;
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,14 @@ import { Section } from 'ts/components/newLayout';
 | 
			
		||||
import { SiteWrap } from 'ts/components/siteWrap';
 | 
			
		||||
import { Heading } from 'ts/components/text';
 | 
			
		||||
import { Input as SearchInput } from 'ts/components/ui/search_textfield';
 | 
			
		||||
import { BY_NAME_ORDERINGS, EDITORIAL, FILTERS, ORDERINGS, PROJECTS } from 'ts/pages/explore/explore_content';
 | 
			
		||||
import {
 | 
			
		||||
    AVAILABLE_ASSET_DATAS,
 | 
			
		||||
    BY_NAME_ORDERINGS,
 | 
			
		||||
    EDITORIAL,
 | 
			
		||||
    FILTERS,
 | 
			
		||||
    ORDERINGS,
 | 
			
		||||
    PROJECTS,
 | 
			
		||||
} from 'ts/pages/explore/explore_content';
 | 
			
		||||
import { ExploreSettingsDropdown } from 'ts/pages/explore/explore_dropdown';
 | 
			
		||||
import { ExploreGrid } from 'ts/pages/explore/explore_grid';
 | 
			
		||||
import { EXPLORE_STATE_DIALOGS, ExploreGridDialogTile } from 'ts/pages/explore/explore_grid_state_tile';
 | 
			
		||||
@@ -70,7 +77,7 @@ export class Explore extends React.Component<ExploreProps> {
 | 
			
		||||
            <SiteWrap theme="light">
 | 
			
		||||
                <DocumentTitle {...documentConstants.EXPLORE} />
 | 
			
		||||
                <ExploreHero query={this.state.query} onSearch={this._setNewQuery} />
 | 
			
		||||
                <Section padding={'0 0 60px 0'} maxWidth={'1150px'}>
 | 
			
		||||
                <Section isPadded={false} padding={'0 0 60px 0'} maxWidth={'1150px'}>
 | 
			
		||||
                    <ExploreToolBar
 | 
			
		||||
                        onFilterClick={this._setFilter}
 | 
			
		||||
                        filters={this.state.filters}
 | 
			
		||||
@@ -115,7 +122,6 @@ export class Explore extends React.Component<ExploreProps> {
 | 
			
		||||
 | 
			
		||||
    private readonly _onOrdering = async (newValue: string): Promise<void> => {
 | 
			
		||||
        this.setState({ tilesOrdering: newValue });
 | 
			
		||||
        // tslint:disable-next-line:no-floating-promises
 | 
			
		||||
        const newTiles = await this._generateTilesWithModifier(this.state.tiles, ExploreTilesModifiers.Ordering, {
 | 
			
		||||
            tilesOrdering: newValue as ExploreTilesOrdering,
 | 
			
		||||
        });
 | 
			
		||||
@@ -127,7 +133,6 @@ export class Explore extends React.Component<ExploreProps> {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private readonly _onAnalytics = (project: ExploreProject, action: ExploreAnalyticAction): void => {
 | 
			
		||||
        // Do Something
 | 
			
		||||
        switch (action) {
 | 
			
		||||
            case ExploreAnalyticAction.InstantClick:
 | 
			
		||||
                analytics.track('Explore - Instant - Clicked', { name: project.name });
 | 
			
		||||
@@ -174,7 +179,6 @@ export class Explore extends React.Component<ExploreProps> {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private readonly _changeSearchResults = async (query: string): Promise<void> => {
 | 
			
		||||
        // tslint:disable-next-line:no-floating-promises
 | 
			
		||||
        const searchedTiles = await this._generateTilesWithModifier(this.state.tiles, ExploreTilesModifiers.Search, {
 | 
			
		||||
            query,
 | 
			
		||||
            filter: this.state.filters.find(f => f.active),
 | 
			
		||||
@@ -196,7 +200,6 @@ export class Explore extends React.Component<ExploreProps> {
 | 
			
		||||
        if (_.filter(updatedFilters, f => f.active).length === 0) {
 | 
			
		||||
            await this._setFilter('all');
 | 
			
		||||
        } else {
 | 
			
		||||
            // tslint:disable-next-line:no-floating-promises
 | 
			
		||||
            const newTiles = await this._generateTilesWithModifier(
 | 
			
		||||
                this.state.tiles,
 | 
			
		||||
                _.isEmpty(this.state.query) ? ExploreTilesModifiers.Filter : ExploreTilesModifiers.Search,
 | 
			
		||||
@@ -284,14 +287,17 @@ export class Explore extends React.Component<ExploreProps> {
 | 
			
		||||
        const tiles = rawProjects.map((e: ExploreProject) => {
 | 
			
		||||
            const exploreProject = _.assign({}, e);
 | 
			
		||||
            if (!!exploreProject.instant) {
 | 
			
		||||
                exploreProject.instant = _.assign({}, exploreProject.instant, {
 | 
			
		||||
                    availableAssetDatas: AVAILABLE_ASSET_DATAS,
 | 
			
		||||
                });
 | 
			
		||||
                exploreProject.onInstantClick = this._launchInstantAsync.bind(this, exploreProject.instant);
 | 
			
		||||
            }
 | 
			
		||||
            exploreProject.onAnalytics = this._onAnalytics.bind(this, exploreProject);
 | 
			
		||||
            return {
 | 
			
		||||
                name: e.name,
 | 
			
		||||
                exploreProject,
 | 
			
		||||
                visibility: ExploreTileVisibility.Visible,
 | 
			
		||||
                width: ExploreTileWidth.OneThird,
 | 
			
		||||
                onAnalytics: this._onAnalytics.bind(this, exploreProject),
 | 
			
		||||
            };
 | 
			
		||||
        });
 | 
			
		||||
        const orderedTiles = await this._generateTilesWithModifier(tiles, ExploreTilesModifiers.Ordering, {
 | 
			
		||||
@@ -307,6 +313,23 @@ const ExploreHeroContentWrapper = styled.div`
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: space-between;
 | 
			
		||||
    padding: 100px 0;
 | 
			
		||||
    @media (max-width: 36rem) {
 | 
			
		||||
        display: block;
 | 
			
		||||
        padding: 50px 0;
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
const ExploreSearchInputWrapper = styled.div`
 | 
			
		||||
    width: 22rem;
 | 
			
		||||
    @media (max-width: 52rem) {
 | 
			
		||||
        width: 16rem;
 | 
			
		||||
    }
 | 
			
		||||
    @media (max-width: 36rem) {
 | 
			
		||||
        margin-top: 10px;
 | 
			
		||||
        padding-left: 5px;
 | 
			
		||||
        width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
interface ExploreHeroProps {
 | 
			
		||||
@@ -319,12 +342,14 @@ const ExploreHero = (props: ExploreHeroProps) => {
 | 
			
		||||
        props.onSearch(e.target.value);
 | 
			
		||||
    };
 | 
			
		||||
    return (
 | 
			
		||||
        <Section maxWidth={'1150px'} padding={'50px 0 50px 0'}>
 | 
			
		||||
        <Section maxWidth={'1150px'} isPadded={false}>
 | 
			
		||||
            <ExploreHeroContentWrapper>
 | 
			
		||||
                <Heading isNoMargin={true} size="large">
 | 
			
		||||
                    Explore 0x
 | 
			
		||||
                </Heading>
 | 
			
		||||
                <SearchInput value={props.query} onChange={onChange} width={'22rem'} placeholder="Search..." />
 | 
			
		||||
                <ExploreSearchInputWrapper>
 | 
			
		||||
                    <SearchInput value={props.query} onChange={onChange} placeholder="Search..." />
 | 
			
		||||
                </ExploreSearchInputWrapper>
 | 
			
		||||
            </ExploreHeroContentWrapper>
 | 
			
		||||
        </Section>
 | 
			
		||||
    );
 | 
			
		||||
@@ -333,11 +358,17 @@ const ExploreHero = (props: ExploreHeroProps) => {
 | 
			
		||||
const ExploreToolBarWrapper = styled.div`
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: space-between;
 | 
			
		||||
    @media (max-width: 36rem) {
 | 
			
		||||
        display: block;
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
const ExploreToolBarContentWrapper = styled.div`
 | 
			
		||||
    display: flex;
 | 
			
		||||
    padding-bottom: 2rem;
 | 
			
		||||
    @media (max-width: 36rem) {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
    & > * {
 | 
			
		||||
        margin: 0 0.3rem;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -126,3 +126,13 @@ export const BY_NAME_ORDERINGS: { [s: string]: string[] } = {
 | 
			
		||||
    [ExploreTilesOrdering.RecentlyAdded]: ['veil', 'boxswap', 'emoon', 'paradex', 'radar_relay', 'openrelay'],
 | 
			
		||||
    [ExploreTilesOrdering.Alphabetical]: ['veil', 'boxswap', 'emoon', 'paradex', 'radar_relay', 'openrelay'],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const AVAILABLE_ASSET_DATAS: string[] = [
 | 
			
		||||
    '0xf47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359', // DAI
 | 
			
		||||
    '0xf47261b0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
 | 
			
		||||
    '0xf47261b00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef', // BAT
 | 
			
		||||
    '0xf47261b000000000000000000000000005f4a42e251f2d52b8ed15e9fedaacfcef1fad27', // ZIL
 | 
			
		||||
    '0xf47261b00000000000000000000000000f5d2fb29fb7d3cfee444a200298f468908cc942', // MANA
 | 
			
		||||
    '0xf47261b00000000000000000000000000abdace70d3790235af448c88547603b945604ea', // DNT
 | 
			
		||||
    '0xf47261b000000000000000000000000041e5560054824ea6b0732e656e3ad64e20e94e45', // CVC
 | 
			
		||||
];
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,13 @@
 | 
			
		||||
import * as React from 'react';
 | 
			
		||||
import styled from 'styled-components';
 | 
			
		||||
 | 
			
		||||
import { Icon } from 'ts/components/icon';
 | 
			
		||||
import { Heading } from 'ts/components/text';
 | 
			
		||||
import { Switch } from 'ts/components/ui/switch';
 | 
			
		||||
import { ExploreTagButton } from 'ts/pages/explore/explore_tag_button';
 | 
			
		||||
import { colors } from 'ts/style/colors';
 | 
			
		||||
import { ExploreTilesOrdering, ExploreTilesOrderingMetadata } from 'ts/types';
 | 
			
		||||
import { ExploreFilterMetadata, ExploreTilesOrdering, ExploreTilesOrderingMetadata } from 'ts/types';
 | 
			
		||||
 | 
			
		||||
const OrderingListWrapper = styled.ul`
 | 
			
		||||
export const OrderingListWrapper = styled.ul`
 | 
			
		||||
    list-style-type: none;
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
@@ -16,7 +15,7 @@ interface OrderingListItemProps {
 | 
			
		||||
    active?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const OrderingListItem = styled.li<OrderingListItemProps>`
 | 
			
		||||
export const OrderingListItem = styled.li<OrderingListItemProps>`
 | 
			
		||||
    margin-bottom: 12px;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    color: ${props => (props.active ? colors.brandLight : colors.grey)};
 | 
			
		||||
@@ -26,13 +25,17 @@ const OrderingListItem = styled.li<OrderingListItemProps>`
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
const ExploreSettingsDropdownButton = ({}) => {
 | 
			
		||||
interface ExploreSettingsDropdownButtonProps {
 | 
			
		||||
    title?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ExploreSettingsDropdownButton = (props: ExploreSettingsDropdownButtonProps) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <ExploreTagButton disableHover={true}>
 | 
			
		||||
            <SettingsIconWrapper>
 | 
			
		||||
                <Icon color={colors.grey} name="settings" size={16} />
 | 
			
		||||
            </SettingsIconWrapper>
 | 
			
		||||
            Sort
 | 
			
		||||
            {props.title || 'Sort'}
 | 
			
		||||
        </ExploreTagButton>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
@@ -45,10 +48,11 @@ const SettingsIconWrapper = styled.div`
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
const SettingsWrapper = styled.div`
 | 
			
		||||
export const SettingsWrapper = styled.div`
 | 
			
		||||
    position: relative;
 | 
			
		||||
 | 
			
		||||
    @media (min-width: 800px) {
 | 
			
		||||
    @media (max-width: 36rem) {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
    &:hover > div {
 | 
			
		||||
        display: block;
 | 
			
		||||
        visibility: visible;
 | 
			
		||||
@@ -56,14 +60,13 @@ const SettingsWrapper = styled.div`
 | 
			
		||||
        transform: translate3d(0, 0, 0);
 | 
			
		||||
        transition: opacity 0.35s, transform 0.35s, visibility 0s;
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
interface DropdownWrapInterface {
 | 
			
		||||
    width?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const DropdownWrap = styled.div<DropdownWrapInterface>`
 | 
			
		||||
export const DropdownWrap = styled.div<DropdownWrapInterface>`
 | 
			
		||||
    width: ${props => props.width || 280}px;
 | 
			
		||||
    margin-top: calc(16px - 2rem);
 | 
			
		||||
    padding: 16px 24px;
 | 
			
		||||
@@ -120,37 +123,43 @@ export interface ExploreSettingsDropdownProps {
 | 
			
		||||
    onOrdering: (newValue: string) => void;
 | 
			
		||||
    onEditorial?: (newValue: boolean) => void;
 | 
			
		||||
    editorial?: boolean;
 | 
			
		||||
    filters: ExploreFilterMetadata[];
 | 
			
		||||
    onFilterClick(filterName: string, active: boolean): void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class ExploreSettingsDropdown extends React.Component<ExploreSettingsDropdownProps> {
 | 
			
		||||
    public render(): React.ReactNode {
 | 
			
		||||
        return (
 | 
			
		||||
            <>
 | 
			
		||||
                <ExploreSettingsFullDropdown {...this.props} />
 | 
			
		||||
                <ExploreMobileSettingsDropdown {...this.props} />
 | 
			
		||||
            </>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ExploreSettingsFullDropdown = (props: ExploreSettingsDropdownProps) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <SettingsWrapper>
 | 
			
		||||
            <ExploreSettingsDropdownButton />
 | 
			
		||||
            <DropdownWrap>
 | 
			
		||||
                <DropdownContentWrapper>
 | 
			
		||||
                        {!!this.props.onEditorial &&
 | 
			
		||||
                    {!!props.onEditorial && (
 | 
			
		||||
                        <div>
 | 
			
		||||
                            <Switch
 | 
			
		||||
                                isChecked={this.props.editorial}
 | 
			
		||||
                                onToggle={this.props.onEditorial}
 | 
			
		||||
                                label="Editorial"
 | 
			
		||||
                            />
 | 
			
		||||
                            <Switch isChecked={props.editorial} onToggle={props.onEditorial} label="Editorial" />
 | 
			
		||||
                            <Heading asElement="h4" size={14} color="inherit" marginBottom="0" isMuted={0.35}>
 | 
			
		||||
                                Editorial content reflects the views of the 0x core team.
 | 
			
		||||
                            </Heading>
 | 
			
		||||
                        </div>}
 | 
			
		||||
                        </div>
 | 
			
		||||
                    )}
 | 
			
		||||
                    <OrderingWrapper>
 | 
			
		||||
                            {/* <Heading asElement="h4" size={14} color="inherit" marginBottom="16px" isMuted={0.35}>
 | 
			
		||||
                                Ordering
 | 
			
		||||
                            </Heading> */}
 | 
			
		||||
                        <OrderingListWrapper>
 | 
			
		||||
                                {this.props.orderings.map(o => {
 | 
			
		||||
                                    const onClick = () => this.props.onOrdering(o.ordering);
 | 
			
		||||
                            {props.orderings.map(o => {
 | 
			
		||||
                                const onClick = () => props.onOrdering(o.ordering);
 | 
			
		||||
                                return (
 | 
			
		||||
                                    <OrderingListItem
 | 
			
		||||
                                        onClick={onClick}
 | 
			
		||||
                                            active={this.props.activeOrdering === o.ordering}
 | 
			
		||||
                                        active={props.activeOrdering === o.ordering}
 | 
			
		||||
                                        key={o.ordering}
 | 
			
		||||
                                    >
 | 
			
		||||
                                        {o.label}
 | 
			
		||||
@@ -163,24 +172,98 @@ export class ExploreSettingsDropdown extends React.Component<ExploreSettingsDrop
 | 
			
		||||
            </DropdownWrap>
 | 
			
		||||
        </SettingsWrapper>
 | 
			
		||||
    );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const DropdownContentWrapper = styled.div``;
 | 
			
		||||
export const DropdownContentWrapper = styled.div``;
 | 
			
		||||
 | 
			
		||||
const OrderingWrapper = styled.div`
 | 
			
		||||
export const OrderingWrapper = styled.div`
 | 
			
		||||
    margin-top: 10px;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    // padding-top: 20px;
 | 
			
		||||
    // margin-bottom: 20px;
 | 
			
		||||
    // &:before {
 | 
			
		||||
    //     content: '';
 | 
			
		||||
    //     width: 100%;
 | 
			
		||||
    //     height: 1px;
 | 
			
		||||
    //     background-color: ${props => props.theme.dropdownColor};
 | 
			
		||||
    //     opacity: 0.15;
 | 
			
		||||
    //     position: absolute;
 | 
			
		||||
    //     top: 0;
 | 
			
		||||
    //     left: 0;
 | 
			
		||||
    // }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
const MobileSettingsWrapper = styled(SettingsWrapper)`
 | 
			
		||||
    display: none;
 | 
			
		||||
    @media (max-width: 36rem) {
 | 
			
		||||
        display: block;
 | 
			
		||||
        & > button {
 | 
			
		||||
            width: 100%;
 | 
			
		||||
        }
 | 
			
		||||
        padding-bottom: 1rem;
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
const MobileDropdownWrap = styled(DropdownWrap)`
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    margin-top: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    &:after,
 | 
			
		||||
    &:before {
 | 
			
		||||
        left: 50%;
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
interface ExploreMobileSettingsDropdownProps extends ExploreSettingsDropdownProps {
 | 
			
		||||
    filters: ExploreFilterMetadata[];
 | 
			
		||||
    onFilterClick(filterName: string, active: boolean): void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ExploreMobileSettingsDropdown = (props: ExploreMobileSettingsDropdownProps) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <MobileSettingsWrapper>
 | 
			
		||||
            <ExploreSettingsDropdownButton title="Filter + Sort" />
 | 
			
		||||
            <MobileDropdownWrap>
 | 
			
		||||
                <DropdownContentWrapper>
 | 
			
		||||
                    <OrderingWrapper>
 | 
			
		||||
                        <Heading asElement="h4" size={14} color="inherit" marginBottom="16px" isMuted={0.35}>
 | 
			
		||||
                            Filter
 | 
			
		||||
                        </Heading>
 | 
			
		||||
                        <OrderingListWrapper>
 | 
			
		||||
                            {props.filters.map(f => {
 | 
			
		||||
                                const onClick = () => props.onFilterClick(f.name, !f.active);
 | 
			
		||||
                                return (
 | 
			
		||||
                                    <OrderingListItem onClick={onClick} active={f.active} key={f.name}>
 | 
			
		||||
                                        {f.label}
 | 
			
		||||
                                    </OrderingListItem>
 | 
			
		||||
                                );
 | 
			
		||||
                            })}
 | 
			
		||||
                        </OrderingListWrapper>
 | 
			
		||||
                    </OrderingWrapper>
 | 
			
		||||
                    <BottomOrderingWrapper>
 | 
			
		||||
                        <Heading asElement="h4" size={14} color="inherit" marginBottom="16px" isMuted={0.35}>
 | 
			
		||||
                            Sort
 | 
			
		||||
                        </Heading>
 | 
			
		||||
                        <OrderingListWrapper>
 | 
			
		||||
                            {props.orderings.map(o => {
 | 
			
		||||
                                const onClick = () => props.onOrdering(o.ordering);
 | 
			
		||||
                                return (
 | 
			
		||||
                                    <OrderingListItem
 | 
			
		||||
                                        onClick={onClick}
 | 
			
		||||
                                        active={props.activeOrdering === o.ordering}
 | 
			
		||||
                                        key={o.ordering}
 | 
			
		||||
                                    >
 | 
			
		||||
                                        {o.label}
 | 
			
		||||
                                    </OrderingListItem>
 | 
			
		||||
                                );
 | 
			
		||||
                            })}
 | 
			
		||||
                        </OrderingListWrapper>
 | 
			
		||||
                    </BottomOrderingWrapper>
 | 
			
		||||
                </DropdownContentWrapper>
 | 
			
		||||
            </MobileDropdownWrap>
 | 
			
		||||
        </MobileSettingsWrapper>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const BottomOrderingWrapper = styled(OrderingWrapper)`
 | 
			
		||||
    margin-top: 20px;
 | 
			
		||||
    padding-top: 20px;
 | 
			
		||||
    &:before {
 | 
			
		||||
        content: '';
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        height: 1px;
 | 
			
		||||
        background-color: ${props => props.theme.dropdownColor};
 | 
			
		||||
        opacity: 0.15;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        top: 0;
 | 
			
		||||
        left: 0;
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,17 +3,44 @@ import * as React from 'react';
 | 
			
		||||
import styled from 'styled-components';
 | 
			
		||||
 | 
			
		||||
import { ExploreGridTile } from 'ts/pages/explore/explore_grid_tile';
 | 
			
		||||
import { ExploreTile, ExploreTileVisibility, ExploreTileWidth } from 'ts/types';
 | 
			
		||||
import { ExploreTile, ExploreTileGridWidth, ExploreTileVisibility, ExploreTileWidth } from 'ts/types';
 | 
			
		||||
 | 
			
		||||
const EXPLORE_TILE_COL_WIDTH: { [ExploreTileWidth: string]: { [ExploreTileGridWidth: number]: number } } = {
 | 
			
		||||
    [ExploreTileWidth.OneThird]: {
 | 
			
		||||
        [ExploreTileGridWidth.ThreeColumn]: 2,
 | 
			
		||||
        [ExploreTileGridWidth.TwoColumn]: 2,
 | 
			
		||||
        [ExploreTileGridWidth.OneColumn]: 2,
 | 
			
		||||
    },
 | 
			
		||||
    [ExploreTileWidth.FullWidth]: {
 | 
			
		||||
        [ExploreTileGridWidth.ThreeColumn]: 6,
 | 
			
		||||
        [ExploreTileGridWidth.TwoColumn]: 4,
 | 
			
		||||
        [ExploreTileGridWidth.OneColumn]: 2,
 | 
			
		||||
    },
 | 
			
		||||
    [ExploreTileWidth.Half]: {
 | 
			
		||||
        [ExploreTileGridWidth.ThreeColumn]: 3,
 | 
			
		||||
        [ExploreTileGridWidth.TwoColumn]: 4,
 | 
			
		||||
        [ExploreTileGridWidth.OneColumn]: 2,
 | 
			
		||||
    },
 | 
			
		||||
    [ExploreTileWidth.TwoThirds]: {
 | 
			
		||||
        [ExploreTileGridWidth.ThreeColumn]: 4,
 | 
			
		||||
        [ExploreTileGridWidth.TwoColumn]: 4,
 | 
			
		||||
        [ExploreTileGridWidth.OneColumn]: 2,
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export interface ExptoreGridProps {
 | 
			
		||||
    tiles: ExploreTile[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface RicherExploreGridListTile extends ExploreTile {
 | 
			
		||||
interface ExploreGridTilePosition {
 | 
			
		||||
    gridStart: number;
 | 
			
		||||
    gridEnd: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface RicherExploreGridListTile extends ExploreTile {
 | 
			
		||||
    tilePositions: { [ExploreTileGridWidth: number]: ExploreGridTilePosition };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class ExploreGrid extends React.Component<ExptoreGridProps> {
 | 
			
		||||
    public render(): React.ReactNode {
 | 
			
		||||
        return (
 | 
			
		||||
@@ -21,13 +48,13 @@ export class ExploreGrid extends React.Component<ExptoreGridProps> {
 | 
			
		||||
                {this._prepareTiles().map(t => {
 | 
			
		||||
                    if (!!t.exploreProject) {
 | 
			
		||||
                        return (
 | 
			
		||||
                            <ExploreGridTileWrapper key={t.name} gridStart={t.gridStart} gridEnd={t.gridEnd}>
 | 
			
		||||
                            <ExploreGridTileWrapper key={t.name} tilePositions={t.tilePositions}>
 | 
			
		||||
                                <ExploreGridTile {...t.exploreProject} />
 | 
			
		||||
                            </ExploreGridTileWrapper>
 | 
			
		||||
                        );
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return (
 | 
			
		||||
                            <ExploreGridTileWrapper key={t.name} gridStart={t.gridStart} gridEnd={t.gridEnd}>
 | 
			
		||||
                            <ExploreGridTileWrapper key={t.name} tilePositions={t.tilePositions}>
 | 
			
		||||
                                {!!t.component && t.component}
 | 
			
		||||
                            </ExploreGridTileWrapper>
 | 
			
		||||
                        );
 | 
			
		||||
@@ -42,18 +69,32 @@ export class ExploreGrid extends React.Component<ExptoreGridProps> {
 | 
			
		||||
        return this._generateGridValues(visibleTiles);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private readonly _generateGridValues = (tiles: ExploreTile[]): RicherExploreGridListTile[] => {
 | 
			
		||||
    private readonly _generateGridPositions = (
 | 
			
		||||
        tiles: RicherExploreGridListTile[],
 | 
			
		||||
        width: ExploreTileGridWidth,
 | 
			
		||||
    ): RicherExploreGridListTile[] => {
 | 
			
		||||
        let gridEndCounter = 1;
 | 
			
		||||
        const richerTiles = tiles.map(t => {
 | 
			
		||||
            if (gridEndCounter + t.width > ExploreTileWidth.FullWidth + 1) {
 | 
			
		||||
        const newTiles = tiles.map(t => {
 | 
			
		||||
            if (gridEndCounter + EXPLORE_TILE_COL_WIDTH[t.width][width] > width + 1) {
 | 
			
		||||
                gridEndCounter = 1;
 | 
			
		||||
            }
 | 
			
		||||
            const gridStart = gridEndCounter;
 | 
			
		||||
            const gridEnd = gridEndCounter + t.width;
 | 
			
		||||
            const gridEnd = gridEndCounter + EXPLORE_TILE_COL_WIDTH[t.width][width];
 | 
			
		||||
            gridEndCounter = gridEnd;
 | 
			
		||||
            const newTile = _.assign({ gridStart, gridEnd }, t);
 | 
			
		||||
            return newTile as RicherExploreGridListTile;
 | 
			
		||||
            const newTilePositions = _.assign({}, t.tilePositions);
 | 
			
		||||
            newTilePositions[width] = { gridStart, gridEnd };
 | 
			
		||||
            return _.assign({}, t, { tilePositions: newTilePositions }) as RicherExploreGridListTile;
 | 
			
		||||
        });
 | 
			
		||||
        return newTiles;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private readonly _generateGridValues = (tiles: ExploreTile[]): RicherExploreGridListTile[] => {
 | 
			
		||||
        let richerTiles = tiles.map(t => {
 | 
			
		||||
            return _.assign({ tilePositions: {} }, t) as RicherExploreGridListTile;
 | 
			
		||||
        });
 | 
			
		||||
        richerTiles = this._generateGridPositions(richerTiles, ExploreTileGridWidth.ThreeColumn);
 | 
			
		||||
        richerTiles = this._generateGridPositions(richerTiles, ExploreTileGridWidth.TwoColumn);
 | 
			
		||||
        richerTiles = this._generateGridPositions(richerTiles, ExploreTileGridWidth.OneColumn);
 | 
			
		||||
        return richerTiles;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
@@ -61,27 +102,34 @@ export class ExploreGrid extends React.Component<ExptoreGridProps> {
 | 
			
		||||
interface ExploreGridListProps {}
 | 
			
		||||
 | 
			
		||||
interface ExploreGridTileWrapperProps {
 | 
			
		||||
    gridStart: number;
 | 
			
		||||
    gridEnd: number;
 | 
			
		||||
    tilePositions: { [ExploreTileGridWidth: number]: ExploreGridTilePosition };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ExploreGridTileWrapper = styled.div<ExploreGridTileWrapperProps>`
 | 
			
		||||
    grid-column-start: ${props => props.gridStart};
 | 
			
		||||
    grid-column-end: ${props => props.gridEnd};
 | 
			
		||||
    grid-column-start: ${props => props.tilePositions[ExploreTileGridWidth.ThreeColumn].gridStart};
 | 
			
		||||
    grid-column-end: ${props => props.tilePositions[ExploreTileGridWidth.ThreeColumn].gridEnd};
 | 
			
		||||
    @media (max-width: 56rem) {
 | 
			
		||||
        grid-column-start: ${props => props.tilePositions[ExploreTileGridWidth.TwoColumn].gridStart};
 | 
			
		||||
        grid-column-end: ${props => props.tilePositions[ExploreTileGridWidth.TwoColumn].gridEnd};
 | 
			
		||||
    }
 | 
			
		||||
    @media (max-width: 36rem) {
 | 
			
		||||
        grid-column-start: ${props => props.tilePositions[ExploreTileGridWidth.OneColumn].gridStart};
 | 
			
		||||
        grid-column-end: ${props => props.tilePositions[ExploreTileGridWidth.OneColumn].gridEnd};
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
const ExploreGridList = styled.div<ExploreGridListProps>`
 | 
			
		||||
    display: grid;
 | 
			
		||||
    grid-template-columns: repeat(${ExploreTileWidth.FullWidth}, 1fr);
 | 
			
		||||
    grid-template-columns: repeat(${ExploreTileGridWidth.ThreeColumn}, 1fr);
 | 
			
		||||
    grid-column-gap: 1.5rem;
 | 
			
		||||
    grid-row-gap: 1.5rem;
 | 
			
		||||
    & > * {
 | 
			
		||||
        align-self: stretch;
 | 
			
		||||
    }
 | 
			
		||||
    @media (max-width: 56rem) {
 | 
			
		||||
        grid-template-columns: repeat(2, 1fr);
 | 
			
		||||
        grid-template-columns: repeat(${ExploreTileGridWidth.TwoColumn}, 1fr);
 | 
			
		||||
    }
 | 
			
		||||
    @media (max-width: 36rem) {
 | 
			
		||||
        grid-template-columns: repeat(1, 1fr);
 | 
			
		||||
        grid-template-columns: repeat(${ExploreTileGridWidth.OneColumn}, 1fr);
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 
 | 
			
		||||
@@ -306,10 +306,16 @@ export enum ExploreTileVisibility {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum ExploreTileWidth {
 | 
			
		||||
    OneThird = 2,
 | 
			
		||||
    FullWidth = 6,
 | 
			
		||||
    Half = 3,
 | 
			
		||||
    TwoThirds = 4,
 | 
			
		||||
    OneThird = 'ONE_THIRD',
 | 
			
		||||
    FullWidth = 'FULL_WIDTH',
 | 
			
		||||
    Half = 'HALF',
 | 
			
		||||
    TwoThirds = 'TWO_THIRDS',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum ExploreTileGridWidth {
 | 
			
		||||
    ThreeColumn = 6,
 | 
			
		||||
    TwoColumn = 4,
 | 
			
		||||
    OneColumn = 2,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ExploreTile {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user