Skip to content

Commit

Permalink
feat: enable categories for worlds (#442)
Browse files Browse the repository at this point in the history
* feat: migrate categorized worlds

* feat: add banner for genesis and worlds

* feat: find worlds using categories

* feat: reusable components for worlds page

* feat: appears on categories

* fix: suggestions

* fix: wrong props

* fix: wrong args
  • Loading branch information
lauti7 authored Feb 22, 2024
1 parent 7ccffcb commit 78f6b08
Show file tree
Hide file tree
Showing 41 changed files with 2,028 additions and 195 deletions.
11 changes: 8 additions & 3 deletions src/api/Places.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import Options from "decentraland-gatsby/dist/utils/api/Options"
import Time from "decentraland-gatsby/dist/utils/date/Time"
import env from "decentraland-gatsby/dist/utils/env"

import { DecentralandCategories } from "../entities/Category/types"
import {
CategoryCountTargetOptions,
DecentralandCategories,
} from "../entities/Category/types"
import {
AggregatePlaceAttributes,
PlaceListOptions,
Expand Down Expand Up @@ -195,11 +198,13 @@ export default class Places extends API {
)
}

async getCategories() {
async getCategories(
target: CategoryCountTargetOptions = CategoryCountTargetOptions.ALL
) {
const result = await super.fetch<{
ok: boolean
data: { name: string; count: number }[]
}>("/categories")
}>(`/categories?target=${target}`)

return result.data
}
Expand Down
62 changes: 62 additions & 0 deletions src/components/Banner/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
.banner {
width: 100%;
height: 172px;
padding-left: 24px;
border-radius: 12px;
justify-content: space-between;
align-items: center;
display: flex;
position: relative;
overflow: hidden;
}

.banner > div {
display: flex;
justify-content: space-between;
gap: 16px;
align-items: center;
}

.banner > div > img {
border-radius: 8px;
width: 64px;
}

.banner > div > div {
display: flex;
flex-direction: column;
}

.banner__title {
color: white;
font-size: 20px;
margin-bottom: 0;
font-weight: 700;
font-family: "Inter";
}

.banner__description {
color: white;
font-size: 16px;
font-weight: 500;
font-family: "Inter";
}

.banner > img {
width: 500px;
height: 172px;
}

.banner > svg {
position: absolute;
right: 16px;
top: 16px;
}

.genesis-banner {
background: linear-gradient(360deg, #ff7562 0%, #b60f55 100%);
}

.worlds-banner {
background: linear-gradient(180deg, #161518 0%, #6c27a1 100%);
}
53 changes: 53 additions & 0 deletions src/components/Banner/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from "react"

import useFormatMessage from "decentraland-gatsby/dist/hooks/useFormatMessage"

import { CategoryCountTargetOptions } from "../../entities/Category/types"
import DCLLogo from "../../images/dcl-logo.svg"
import GenesisBanner from "../../images/genesis-banner.png"
import WorldBanner from "../../images/worlds-banner.png"
import WorldsLogo from "../../images/worlds-logo.svg"
import { Close } from "../Icon/Close"

import "./index.css"

type BannerProps = {
type: CategoryCountTargetOptions.PLACES | CategoryCountTargetOptions.WORLDS
onClose: (e: React.MouseEvent<SVGElement, MouseEvent>) => void
}

export default ({ onClose, type }: BannerProps) => {
const l = useFormatMessage()

return (
<div
className={`banner ${
type === CategoryCountTargetOptions.PLACES
? "genesis-banner"
: "worlds-banner"
}`}
>
<div>
<img
src={
type === CategoryCountTargetOptions.PLACES ? DCLLogo : WorldsLogo
}
/>
<div>
<p className="banner__title">{l(`pages.${type}.banner.title`)}</p>
<p className="banner__description">
{l(`pages.${type}.banner.description`)}
</p>
</div>
</div>
<img
src={
type === CategoryCountTargetOptions.PLACES
? GenesisBanner
: WorldBanner
}
/>
<Close width="32" height="32" type="filled" onClick={onClose} />
</div>
)
}
61 changes: 61 additions & 0 deletions src/components/BannerMobile/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
.banner-mobile {
max-width: 346px;
width: 100%;
height: 316px;
background: linear-gradient(180deg, #161518 0%, #6c27a1 100%);
border-radius: 16px;
overflow: hidden;
flex-direction: column;
justify-content: flex-start;
align-items: center;
display: flex;
margin: auto;
position: relative;
}

.banner-mobile > div {
padding: 24px 12px;
display: flex;
flex-direction: column;
gap: 4px;
align-items: center;
text-align: center;
}

.banner-mobile > div > img {
width: 40px;
height: 40px;
border-radius: 8px;
}

.banner-mobile__title {
color: white;
font-size: 20px;
font-weight: 700;
margin-bottom: 0;
}

.banner-mobile__description {
color: white;
font-size: 16px;
font-weight: 500;
}

.banner-mobile > img {
width: 346px;
height: 132px;
}

.banner-mobile > svg {
position: absolute;
top: 6px;
right: 6px;
}

.genesis-banner-mobile {
background: linear-gradient(360deg, #ff7562 0%, #b60f55 100%);
}

.worlds-banner-mobile {
background: linear-gradient(180deg, #161518 0%, #6c27a1 100%);
}
54 changes: 54 additions & 0 deletions src/components/BannerMobile/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from "react"

import useFormatMessage from "decentraland-gatsby/dist/hooks/useFormatMessage"

import { CategoryCountTargetOptions } from "../../entities/Category/types"
import DCLLogo from "../../images/dcl-logo.svg"
import GenesisBanner from "../../images/genesis-banner-mobile.png"
import WorldBanner from "../../images/worlds-banner.png"
import WorldsLogo from "../../images/worlds-logo.svg"
import { Close } from "../Icon/Close"

import "./index.css"

type BannerMobileProps = {
type: CategoryCountTargetOptions.PLACES | CategoryCountTargetOptions.WORLDS
onClose: (e: React.MouseEvent<SVGElement, MouseEvent>) => void
}

export default ({ type, onClose }: BannerMobileProps) => {
const l = useFormatMessage()

return (
<div
className={`banner-mobile ${
type === CategoryCountTargetOptions.PLACES
? "genesis-banner-mobile"
: "worlds-banner-mobile"
}`}
>
<div>
<img
src={
type === CategoryCountTargetOptions.WORLDS ? WorldsLogo : DCLLogo
}
alt="Decentraland Logo"
/>
<p className="banner-mobile__title">
{l(`pages.${type}.banner.title`)}
</p>
<p className="banner-mobile__description">
{l(`pages.${type}.banner.description`)}
</p>
</div>
<img
src={
type === CategoryCountTargetOptions.WORLDS
? WorldBanner
: GenesisBanner
}
/>
<Close width="32" height="32" type="filled" onClick={onClose} />
</div>
)
}
12 changes: 12 additions & 0 deletions src/components/Category/AppearsOnCategory.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.appears-on-categories-container {
border-top: solid 1px rgba(115, 110, 125, 0.24);
width: 100%;
padding: 25px 20px;
}

.appears-on-categories-container
.category-filter__box
.dcl.filter
.filter-background {
background: var(--secondary-on-modal);
}
33 changes: 33 additions & 0 deletions src/components/Category/AppearsOnCategory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react"

import useFormatMessage from "decentraland-gatsby/dist/hooks/useFormatMessage"

import { CategoryFilter, CategoryFilterProps } from "./CategoryFilter"

import "./AppearsOnCategory.css"

type AppearsOnCategoryProps = {
categories: string[]
onSelectCategory: (
e: React.MouseEvent<HTMLSpanElement, MouseEvent>,
props: CategoryFilterProps
) => void
}

const AppearsOnCategory = ({
categories,
onSelectCategory,
}: AppearsOnCategoryProps) => {
const l = useFormatMessage()

return (
<div className="appears-on-categories-container">
<h3>{l("components.place_detail.appears_on")}</h3>
{categories.map((id) => (
<CategoryFilter category={id} onChange={onSelectCategory} />
))}
</div>
)
}

export default AppearsOnCategory
20 changes: 15 additions & 5 deletions src/components/Category/CategoryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,29 @@ type CategoryList = {
props: CategoryFilterProps
) => void
categories: Category[]
label: string
applyfilter?: boolean
isNew?: boolean
}

export const CategoryList = React.memo((props: CategoryList) => {
const { categories, onChange } = props
const { categories, onChange, isNew, label } = props
const l = useFormatMessage()

return (
<div className="category-list__box">
<NewLabel
title={l("categories.title")}
className="category-list__title"
/>
{isNew ? (
<NewLabel
title={`${label} ${l("categories.title")}`}
className="category-list__title"
/>
) : (
<div className="category-list__title">
<p>
{label} {l("categories.title")}
</p>
</div>
)}
<CategoryFilters
categories={categories}
onChange={onChange}
Expand Down
9 changes: 9 additions & 0 deletions src/components/Category/OnlyViewCategoryNavbar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.only-view-category-navbar__box {
display: flex;
align-items: center;
margin-bottom: 10px;
}

.only-view-category-navbar__box > .dcl.back {
margin-right: 5px;
}
39 changes: 39 additions & 0 deletions src/components/Category/OnlyViewCategoryNavbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from "react"

import { Back } from "decentraland-ui/dist/components/Back/Back"

import { Close } from "../Icon/Close"
import { CategoryFilter, CategoryFilterProps } from "./CategoryFilter"

import "./OnlyViewCategoryNavbar.css"

type OnlyViewCategoryNavbarPros = {
category: string
onClickBack: (e: React.MouseEvent<Element, MouseEvent>) => void
onClickCategoryFilter: (
e: React.MouseEvent<HTMLSpanElement, MouseEvent>,
props: CategoryFilterProps
) => void
}

const OnlyViewCategoryNavbar = ({
category,
onClickBack,
onClickCategoryFilter,
}: OnlyViewCategoryNavbarPros) => {
return (
<div className="only-view-category-navbar__box">
<Back onClick={onClickBack} />
<div>
<CategoryFilter
category={category}
active
onChange={onClickCategoryFilter}
actionIcon={<Close width="20" height="20" />}
/>
</div>
</div>
)
}

export default OnlyViewCategoryNavbar
Loading

0 comments on commit 78f6b08

Please sign in to comment.