From ab3e22e4bf9514c0c5a73e35fbcb2f528af589f2 Mon Sep 17 00:00:00 2001 From: 1emu Date: Thu, 27 Jun 2024 16:14:26 -0300 Subject: [PATCH] feat: add floating header and other statuses to project hero --- .../FloatingHeader/FloatingHeader.css | 2 +- .../FloatingHeader/FloatingHeader.tsx | 15 ++--- .../{ProjectViewTitle.css => ProjectHero.css} | 10 +++- src/components/Projects/ProjectHero.tsx | 56 +++++++++++++++++++ src/components/Projects/ProjectView.tsx | 12 ++-- .../Projects/ProjectViewStatusPill.css | 9 ++- src/components/Projects/ProjectViewTitle.tsx | 56 ------------------- src/pages/project.tsx | 34 ++++++++++- src/pages/proposal.tsx | 15 ++++- 9 files changed, 130 insertions(+), 79 deletions(-) rename src/components/Projects/{ProjectViewTitle.css => ProjectHero.css} (96%) create mode 100644 src/components/Projects/ProjectHero.tsx delete mode 100644 src/components/Projects/ProjectViewTitle.tsx diff --git a/src/components/FloatingHeader/FloatingHeader.css b/src/components/FloatingHeader/FloatingHeader.css index a83174f..5f703e8 100644 --- a/src/components/FloatingHeader/FloatingHeader.css +++ b/src/components/FloatingHeader/FloatingHeader.css @@ -45,7 +45,7 @@ padding-left: 14px; } -.FloatingHeader__Status { +.FloatingHeader__Body { display: flex; gap: 8px; min-height: 24px; diff --git a/src/components/FloatingHeader/FloatingHeader.tsx b/src/components/FloatingHeader/FloatingHeader.tsx index 8baf13e..9ac2510 100644 --- a/src/components/FloatingHeader/FloatingHeader.tsx +++ b/src/components/FloatingHeader/FloatingHeader.tsx @@ -1,26 +1,21 @@ import classNames from 'classnames' -import { ProposalAttributes } from '../../types/proposals' -import CategoryPill from '../Category/CategoryPill' import WiderContainer from '../Common/WiderContainer' -import StatusPill from '../Status/StatusPill' import './FloatingHeader.css' interface FloatingHeaderProps { isVisible: boolean - proposal: ProposalAttributes + title: string + children?: React.ReactNode } -const FloatingHeader = ({ isVisible, proposal }: FloatingHeaderProps) => { +const FloatingHeader = ({ isVisible, title, children }: FloatingHeaderProps) => { return (
-
{proposal?.title}
-
- - -
+
{title}
+
{children}
diff --git a/src/components/Projects/ProjectViewTitle.css b/src/components/Projects/ProjectHero.css similarity index 96% rename from src/components/Projects/ProjectViewTitle.css rename to src/components/Projects/ProjectHero.css index bb69499..762d756 100644 --- a/src/components/Projects/ProjectViewTitle.css +++ b/src/components/Projects/ProjectHero.css @@ -35,7 +35,6 @@ } .ProjectHero__Title { - color: var(--white-900); font-weight: var(--weight-semi-bold); font-size: 18px; line-height: 26px; @@ -45,6 +44,10 @@ margin: 8px 0; } +.ProjectHero__Title--active { + color: var(--white-900); +} + @media (min-width: 768px) { .ProjectHero__Title { margin-bottom: 0.3em; @@ -57,11 +60,14 @@ } .ProjectHero__Banner { - background: linear-gradient(90deg, #d80027 0%, #a524b3 100%); box-shadow: none; border-radius: 8px; } +.ProjectHero__Banner--active { + background: linear-gradient(90deg, #d80027 0%, #a524b3 100%); +} + @media (min-width: 768px) { .ProjectHero__Banner { border-radius: 6px; diff --git a/src/components/Projects/ProjectHero.tsx b/src/components/Projects/ProjectHero.tsx new file mode 100644 index 0000000..da43ecc --- /dev/null +++ b/src/components/Projects/ProjectHero.tsx @@ -0,0 +1,56 @@ +import { Ref, forwardRef } from 'react' + +import classNames from 'classnames' +import { Loader } from 'decentraland-ui/dist/components/Loader/Loader' + +import { ProjectStatus } from '../../types/grants.ts' +import { Project } from '../../types/proposals.ts' +import { PillColor } from '../Common/Pill.tsx' +import DotsMenu from '../Icon/DotsMenu.tsx' +import SlimCross from '../Icon/SlimCross.tsx' +import HeroBanner from '../Proposal/HeroBanner.tsx' + +import './ProjectHero.css' +import ProjectViewStatusPill from './ProjectViewStatusPill.tsx' + +const IS_DOTS_MENU_ENABLED = false + +interface Props { + project: Project + onClose?: () => void +} + +const HIGHLIGHTED_STATUSES = [ProjectStatus.Pending, ProjectStatus.InProgress] + +const ProjectHero = forwardRef(({ project, onClose }: Props, ref: Ref) => { + const active = HIGHLIGHTED_STATUSES.includes(project.status) + + return ( + <> +
+ +
+

+ {project?.title || ''} +

+ + {project && } +
+
+ {IS_DOTS_MENU_ENABLED && } + {onClose && ( + + )} +
+
+ + ) +}) + +ProjectHero.displayName = 'ProjectHero' + +export default ProjectHero diff --git a/src/components/Projects/ProjectView.tsx b/src/components/Projects/ProjectView.tsx index 7a7477b..9c0eaf9 100644 --- a/src/components/Projects/ProjectView.tsx +++ b/src/components/Projects/ProjectView.tsx @@ -1,4 +1,4 @@ -import { useMemo, useState } from 'react' +import { Ref, forwardRef, useMemo, useState } from 'react' import useFormatMessage from '../../hooks/useFormatMessage' import useShowProjectUpdatesCta from '../../hooks/useShowProjectUpdatesCta.ts' @@ -12,17 +12,17 @@ import UpdatesTabView from './Updates/UpdatesTabView' import MilestonesTab from './MilestonesTab' import ProjectGeneralInfo from './ProjectGeneralInfo' +import ProjectHero from './ProjectHero' import ProjectVerticalTab from './ProjectVerticalTab.tsx' import './ProjectView.css' import ProjectViewFundingSection from './ProjectViewFundingSection.tsx' -import ProjectViewTitle from './ProjectViewTitle' interface Props { project?: Project | null onClose?: () => void } -function ProjectView({ project, onClose }: Props) { +const ProjectView = forwardRef(({ project, onClose }: Props, ref: Ref) => { const t = useFormatMessage() const [viewIdx, setViewIdx] = useState(0) const showMilestonesTab = !( @@ -56,7 +56,7 @@ function ProjectView({ project, onClose }: Props) { return (
- {project && } + {project && } {project && (
@@ -89,6 +89,8 @@ function ProjectView({ project, onClose }: Props) {
) -} +}) + +ProjectView.displayName = 'ProjectView' export default ProjectView diff --git a/src/components/Projects/ProjectViewStatusPill.css b/src/components/Projects/ProjectViewStatusPill.css index 6b07f8c..c9d3cd9 100644 --- a/src/components/Projects/ProjectViewStatusPill.css +++ b/src/components/Projects/ProjectViewStatusPill.css @@ -25,17 +25,20 @@ background: var(--black-200); } -.ProjectViewStatusPill--revoked { +.ProjectViewStatusPill--revoked, +.ProjectViewStatusPill--revoked--hero { color: var(--red-800); background: var(--red-200); } -.ProjectViewStatusPill--finished { +.ProjectViewStatusPill--finished, +.ProjectViewStatusPill--finished--hero { color: var(--green-900); background: var(--green-200); } -.ProjectViewStatusPill--paused { +.ProjectViewStatusPill--paused, +.ProjectViewStatusPill--paused--hero { color: var(--orange-800); background: var(--orange-200); } diff --git a/src/components/Projects/ProjectViewTitle.tsx b/src/components/Projects/ProjectViewTitle.tsx deleted file mode 100644 index 9185f0d..0000000 --- a/src/components/Projects/ProjectViewTitle.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Loader } from 'decentraland-ui/dist/components/Loader/Loader' - -import { ProjectStatus } from '../../types/grants.ts' -import { Project } from '../../types/proposals.ts' -import { PillColor } from '../Common/Pill.tsx' -import DotsMenu from '../Icon/DotsMenu.tsx' -import SlimCross from '../Icon/SlimCross.tsx' -import HeroBanner from '../Proposal/HeroBanner.tsx' - -import ProjectViewStatusPill from './ProjectViewStatusPill.tsx' -import './ProjectViewTitle.css' - -const IS_DOTS_MENU_ENABLED = false - -interface Props { - project: Project - onClose?: () => void -} - -const HIGHLIGHTED_STATUSES = [ProjectStatus.Pending, ProjectStatus.InProgress] - -export default function ProjectViewTitle({ project, onClose }: Props) { - const showHero = HIGHLIGHTED_STATUSES.includes(project.status) - - return ( - <> - {showHero ? ( -
- -
-

{project?.title || ''}

- - {project && } -
-
- {IS_DOTS_MENU_ENABLED && } - {onClose && ( - - )} -
-
- ) : ( -
- {project?.title || ''} -
- - {IS_DOTS_MENU_ENABLED && } - {onClose && ( - - )} -
-
- )} - - ) -} diff --git a/src/pages/project.tsx b/src/pages/project.tsx index e6de188..12dc13c 100644 --- a/src/pages/project.tsx +++ b/src/pages/project.tsx @@ -1,9 +1,15 @@ +import { useEffect, useRef, useState } from 'react' + +import { NotMobile } from 'decentraland-ui/dist/components/Media/Media' + import WiderContainer from '../components/Common/WiderContainer' +import FloatingHeader from '../components/FloatingHeader/FloatingHeader.tsx' import Head from '../components/Layout/Head' import LoadingView from '../components/Layout/LoadingView' import Navigation, { NavigationTab } from '../components/Layout/Navigation' import NotFound from '../components/Layout/NotFound' import ProjectView from '../components/Projects/ProjectView' +import ProjectViewStatusPill from '../components/Projects/ProjectViewStatusPill.tsx' import useProject from '../hooks/useProject' import useURLSearchParams from '../hooks/useURLSearchParams' import locations from '../utils/locations' @@ -11,10 +17,29 @@ import locations from '../utils/locations' export default function ProjectPage() { const params = useURLSearchParams() const { project, isLoadingProject } = useProject(params.get('id')) + const [isFloatingHeaderVisible, setIsFloatingHeaderVisible] = useState(true) + const heroSectionRef = useRef(null) const title = project?.title || '' const description = project?.about || '' + useEffect(() => { + setIsFloatingHeaderVisible(false) + if (!isLoadingProject && typeof window !== 'undefined') { + const handleScroll = () => { + if (!!heroSectionRef.current && !!window) { + const { top: heroSectionTop, height: heroSectionHeight } = heroSectionRef.current.getBoundingClientRect() + setIsFloatingHeaderVisible(heroSectionTop + heroSectionHeight / 2 < 0) + } + } + + window.addEventListener('scroll', handleScroll) + return () => { + window.removeEventListener('scroll', handleScroll) + } + } + }, [isLoadingProject]) + if (isLoadingProject) { return ( <> @@ -41,8 +66,15 @@ export default function ProjectPage() { links={[{ rel: 'canonical', href: locations.project({ id: project?.id }) }]} /> + + {project && ( + + + + )} + - + ) diff --git a/src/pages/proposal.tsx b/src/pages/proposal.tsx index 1456232..52d1dbe 100644 --- a/src/pages/proposal.tsx +++ b/src/pages/proposal.tsx @@ -9,6 +9,7 @@ import { Desktop, NotMobile, TabletAndBelow } from 'decentraland-ui/dist/compone import { ErrorClient } from '../clients/ErrorClient' import { Governance } from '../clients/Governance' import { SnapshotApi } from '../clients/SnapshotApi' +import CategoryPill from '../components/Category/CategoryPill.tsx' import ProposalVPChart from '../components/Charts/ProposalVPChart' import WiderContainer from '../components/Common/WiderContainer' import FloatingBar from '../components/FloatingBar/FloatingBar' @@ -43,6 +44,7 @@ import GovernanceProcess from '../components/Proposal/View/GovernanceProcess' import ProposalDetailSection from '../components/Proposal/View/ProposalDetailSection' import ProposalImagesPreview from '../components/Proposal/View/ProposalImagesPreview' import ProposalMarkdown from '../components/Proposal/View/ProposalMarkdown' +import StatusPill from '../components/Status/StatusPill.tsx' import { useAuthContext } from '../context/AuthProvider' import { DEFAULT_QUERY_STALE_TIME } from '../hooks/constants' import useAsyncTask from '../hooks/useAsyncTask' @@ -360,7 +362,18 @@ export default function ProposalPage() { links={[{ rel: 'canonical', href: locations.proposal(proposal?.id || '') }]} /> - {proposal && } + + {proposal && ( + + { + <> + + + + } + + )} + {proposal && (