From 519c375a42ee9df72a9c1f3df9fd878e1a12a5a1 Mon Sep 17 00:00:00 2001 From: David Sun Date: Tue, 19 Mar 2019 17:55:41 -0400 Subject: [PATCH] added responsive features --- .../ts/components/annoucement_banner.tsx | 73 +++--- packages/website/ts/components/newLayout.tsx | 2 +- .../ts/components/ui/search_textfield.tsx | 4 - packages/website/ts/pages/explore.tsx | 49 +++- .../ts/pages/explore/explore_content.tsx | 10 + .../ts/pages/explore/explore_dropdown.tsx | 219 ++++++++++++------ .../website/ts/pages/explore/explore_grid.tsx | 82 +++++-- packages/website/ts/types.ts | 14 +- 8 files changed, 323 insertions(+), 130 deletions(-) diff --git a/packages/website/ts/components/annoucement_banner.tsx b/packages/website/ts/components/annoucement_banner.tsx index aae1bcfc50..b51f6308d0 100644 --- a/packages/website/ts/components/annoucement_banner.tsx +++ b/packages/website/ts/components/annoucement_banner.tsx @@ -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) => { const { heading, subline, mainCta, secondaryCta } = props; @@ -43,9 +43,9 @@ export const AnnouncementBanner: React.StatelessComponent = (props: Props {heading} {subline && ( - + {subline} - + )} @@ -72,15 +72,17 @@ export const AnnouncementBanner: React.StatelessComponent = (props: Props )} {secondaryCta && ( - + + + )} @@ -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)` @@ -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` 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; diff --git a/packages/website/ts/components/newLayout.tsx b/packages/website/ts/components/newLayout.tsx index ebe976d8ea..fa7123767f 100644 --- a/packages/website/ts/components/newLayout.tsx +++ b/packages/website/ts/components/newLayout.tsx @@ -93,7 +93,7 @@ const SectionBase = styled.section` 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'}; diff --git a/packages/website/ts/components/ui/search_textfield.tsx b/packages/website/ts/components/ui/search_textfield.tsx index 367d7d3ac7..6faca1a689 100644 --- a/packages/website/ts/components/ui/search_textfield.tsx +++ b/packages/website/ts/components/ui/search_textfield.tsx @@ -56,8 +56,4 @@ const InputWrapper = styled.div` position: relative; width: ${props => props.width || '100%'}; border-bottom: 1px solid #d5d5d5; - @media (max-width: 768px) { - width: 100%; - margin-bottom: 30px; - } `; diff --git a/packages/website/ts/pages/explore.tsx b/packages/website/ts/pages/explore.tsx index 63c9a35e19..571f30733d 100644 --- a/packages/website/ts/pages/explore.tsx +++ b/packages/website/ts/pages/explore.tsx @@ -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 { -
+
{ private readonly _onOrdering = async (newValue: string): Promise => { 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 { }; 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 { }; private readonly _changeSearchResults = async (query: string): Promise => { - // 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 { 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 { 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 ( -
+
Explore 0x - + + +
); @@ -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; } diff --git a/packages/website/ts/pages/explore/explore_content.tsx b/packages/website/ts/pages/explore/explore_content.tsx index f7c5a9b117..76bbf8d3cb 100644 --- a/packages/website/ts/pages/explore/explore_content.tsx +++ b/packages/website/ts/pages/explore/explore_content.tsx @@ -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 +]; diff --git a/packages/website/ts/pages/explore/explore_dropdown.tsx b/packages/website/ts/pages/explore/explore_dropdown.tsx index a3470ea774..359490345d 100644 --- a/packages/website/ts/pages/explore/explore_dropdown.tsx +++ b/packages/website/ts/pages/explore/explore_dropdown.tsx @@ -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` +export const OrderingListItem = styled.li` margin-bottom: 12px; cursor: pointer; color: ${props => (props.active ? colors.brandLight : colors.grey)}; @@ -26,13 +25,17 @@ const OrderingListItem = styled.li` } `; -const ExploreSettingsDropdownButton = ({}) => { +interface ExploreSettingsDropdownButtonProps { + title?: string; +} + +export const ExploreSettingsDropdownButton = (props: ExploreSettingsDropdownButtonProps) => { return ( - Sort + {props.title || 'Sort'} ); }; @@ -45,17 +48,17 @@ const SettingsIconWrapper = styled.div` } `; -const SettingsWrapper = styled.div` +export const SettingsWrapper = styled.div` position: relative; - - @media (min-width: 800px) { - &:hover > div { - display: block; - visibility: visible; - opacity: 1; - transform: translate3d(0, 0, 0); - transition: opacity 0.35s, transform 0.35s, visibility 0s; - } + @media (max-width: 36rem) { + display: none; + } + &:hover > div { + display: block; + visibility: visible; + opacity: 1; + transform: translate3d(0, 0, 0); + transition: opacity 0.35s, transform 0.35s, visibility 0s; } `; @@ -63,7 +66,7 @@ interface DropdownWrapInterface { width?: number; } -const DropdownWrap = styled.div` +export const DropdownWrap = styled.div` width: ${props => props.width || 280}px; margin-top: calc(16px - 2rem); padding: 16px 24px; @@ -120,67 +123,147 @@ 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 { public render(): React.ReactNode { return ( - - - - - {!!this.props.onEditorial && -
- - - Editorial content reflects the views of the 0x core team. - -
} - - {/* - Ordering - */} - - {this.props.orderings.map(o => { - const onClick = () => this.props.onOrdering(o.ordering); - return ( - - {o.label} - - ); - })} - - -
-
-
+ <> + + + ); } } -const DropdownContentWrapper = styled.div``; +const ExploreSettingsFullDropdown = (props: ExploreSettingsDropdownProps) => { + return ( + + + + + {!!props.onEditorial && ( +
+ + + Editorial content reflects the views of the 0x core team. + +
+ )} + + + {props.orderings.map(o => { + const onClick = () => props.onOrdering(o.ordering); + return ( + + {o.label} + + ); + })} + + +
+
+
+ ); +}; -const OrderingWrapper = styled.div` +export const DropdownContentWrapper = 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 ( + + + + + + + Filter + + + {props.filters.map(f => { + const onClick = () => props.onFilterClick(f.name, !f.active); + return ( + + {f.label} + + ); + })} + + + + + Sort + + + {props.orderings.map(o => { + const onClick = () => props.onOrdering(o.ordering); + return ( + + {o.label} + + ); + })} + + + + + + ); +}; + +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; + } `; diff --git a/packages/website/ts/pages/explore/explore_grid.tsx b/packages/website/ts/pages/explore/explore_grid.tsx index 2ce1268747..7121c39c4c 100644 --- a/packages/website/ts/pages/explore/explore_grid.tsx +++ b/packages/website/ts/pages/explore/explore_grid.tsx @@ -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 { public render(): React.ReactNode { return ( @@ -21,13 +48,13 @@ export class ExploreGrid extends React.Component { {this._prepareTiles().map(t => { if (!!t.exploreProject) { return ( - + ); } else { return ( - + {!!t.component && t.component} ); @@ -42,18 +69,32 @@ export class ExploreGrid extends React.Component { 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 { interface ExploreGridListProps {} interface ExploreGridTileWrapperProps { - gridStart: number; - gridEnd: number; + tilePositions: { [ExploreTileGridWidth: number]: ExploreGridTilePosition }; } const ExploreGridTileWrapper = styled.div` - 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` 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); } `; diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index f900150717..fd1a151dcb 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -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 {