update: unify category filter, update projects sorting, update nav logo

This commit is contained in:
MTG2000
2022-11-08 11:24:48 +02:00
parent 3027c8a7f5
commit a78e41a7b2
11 changed files with 44 additions and 46 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -41,8 +41,9 @@ export default function NavDesktop() {
<div className="content-container">
<div className="flex items-center">
<Link to="/">
<h2 className="text-h5 font-bold mr-40 lg:mr-64">
<img className='h-40' src={ASSETS.Logo} alt="Bolt fun logo" />
<h2 className="text-body5 md:text-h5 font-bold mr-24 md:mr-40 lg:mr-64 flex items-center gap-16">
<img className='h-40' src={ASSETS.LogoLight} alt="Lightning Landscape Logo" />
<span className="font-extrabold">Lightning Landscape</span>
</h2>
</Link>
<Button color="primary" size="sm" variant="text" className="ml-auto">Submit project <BiRocket /></Button>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -3,7 +3,8 @@ import Images_ExploreHeader2 from './images/shock-the-web.jpg'
import Category_BG from './images/category-bg.jpg'
import Image_Hottest_Header from './images/hottest.jfif'
import Logo from './images/logo.png'
import LogoLight from './images/logo-light.png'
const ASSETS = { Images_ExploreHeader1, Images_ExploreHeader2, Image_Hottest_Header, Logo, Category_BG }
const ASSETS = { Images_ExploreHeader1, Images_ExploreHeader2, Image_Hottest_Header, Logo, LogoLight, Category_BG }
export default ASSETS;

View File

@@ -1,6 +1,6 @@
import { useNavigate } from 'react-router-dom';
import { CategoryList, useAllCategoriesQuery } from 'src/graphql';
import { CategoryList, useAllCategoriesQuery, useGetFiltersQuery } from 'src/graphql';
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
import { useCarousel } from 'src/utils/hooks';
import Skeleton from 'react-loading-skeleton';
@@ -31,7 +31,7 @@ export default function Categories(props: Props) {
align: 'start', slidesToScroll: 2,
containScroll: "trimSnaps",
})
const { data, loading } = useAllCategoriesQuery();
const { data, loading } = useGetFiltersQuery();
if (loading || !data)

View File

@@ -4,7 +4,7 @@ import { useExplorePageQuery } from 'src/graphql';
import ProjectsGrid from './ProjectsGrid/ProjectsGrid';
import { Helmet } from "react-helmet";
import Categories, { Category } from '../../Components/Categories/Categories';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useCallback, useMemo, useRef, useState } from 'react';
import Header from './Header/Header';
import Button from 'src/Components/Button/Button';
import { useAppDispatch } from 'src/utils/hooks';
@@ -15,7 +15,7 @@ import { NetworkStatus } from '@apollo/client';
import { FiSliders } from 'react-icons/fi';
import { HiOutlineChevronDoubleDown } from 'react-icons/hi'
import { ProjectsFilters } from './Filters/FiltersModal';
import { getFiltersFromUrl, useUpdateUrlWithFilters } from './helpers';
import { useUpdateUrlWithFilters } from './helpers';
import { withBasicProvider } from 'src/utils/helperFunctions';
import { ProjectsFiltersProvider, useProjectsFilters } from './filters-context';
@@ -35,12 +35,9 @@ const PAGE_SIZE = 28;
function ExplorePage() {
const dispatch = useAppDispatch();
const { filters, updateFilters } = useProjectsFilters();
const [selectedCategory, setSelectedCategory] = useState<Category | null>(null)
const projectsLength = useRef<number>(0);
const [showDeadProjects, setShowDeadProjects] = useState(false)
const [canFetchMore, setCanFetchMore] = useState(true);
useUpdateUrlWithFilters(filters)
@@ -50,13 +47,12 @@ function ExplorePage() {
let filter: QueryFilter = {}
let hasSearchFilters = false;
const defaultFilters = {} as const;
if (filters?.categories) {
filter.categoryId = filters?.categories.map(c => c.id);
filter.categoryId = filters?.categories.map(c => c.id!);
hasSearchFilters = true;
}
if (selectedCategory?.id) filter.categoryId = [selectedCategory?.id]
if (filters?.tags) {
filter.tags = filters?.tags.map(t => t.id)
@@ -83,7 +79,7 @@ function ExplorePage() {
return { queryFilters: null, hasSearchFilters }
return { queryFilters: filter, hasSearchFilters };
}, [filters, selectedCategory?.id])
}, [filters])
const { data, networkStatus, error, fetchMore } = useExplorePageQuery({
variables: {
@@ -102,7 +98,6 @@ function ExplorePage() {
const onFiltersUpdated = useCallback(({ payload }: typeof UPDATE_FILTERS_ACTION) => {
setSelectedCategory(null)
setCanFetchMore(true);
updateFilters(payload)
}, [updateFilters])
@@ -129,11 +124,7 @@ function ExplorePage() {
}
const selectCategoryTab = (category: Category | null) => {
if (filters) {
const { categories, ...filtersWithoutCategory } = filters
updateFilters(filtersWithoutCategory)
}
setSelectedCategory(category);
updateFilters({ ...(filters ?? {}), categories: category ? [category] : undefined })
setCanFetchMore(true);
}
@@ -150,9 +141,6 @@ function ExplorePage() {
</div>
}
const deadProjectsCount = data?.projects?.filter(p => p?.dead).length;
const hasDeadProjectsFilter = filters?.projectStatus === 'dead';
const isLoading = networkStatus === NetworkStatus.loading || networkStatus === NetworkStatus.refetch || networkStatus === NetworkStatus.setVariables;
const isLoadingMore = networkStatus === NetworkStatus.fetchMore;
const canLoadMore = !isLoading && !isLoadingMore && data?.projects && data.projects.length > 0 && canFetchMore;
@@ -165,11 +153,11 @@ function ExplorePage() {
<meta property="og:title" content={`Lightning Landscape`} />
</Helmet>
<Header
selectedCategry={selectedCategory}
selectedCategry={filters?.categories?.[0] ?? null}
/>
<div className="page-container">
<div className="grid grid-cols-1 md:grid-cols-[1fr_auto] items-center gap-x-32 gap-y-16 mb-36">
<div className="min-w-0 max-md:row-start-2"><Categories filtersActive={hasSearchFilters} value={selectedCategory} onChange={v => selectCategoryTab(v)} /></div>
<div className="min-w-0 max-md:row-start-2"><Categories filtersActive={hasSearchFilters} value={filters?.categories?.[0] ?? null} onChange={v => selectCategoryTab(v)} /></div>
<Button
className={`self-center ${hasSearchFilters ? "!font-bold !bg-primary-50 !text-primary-600 !border-2 !border-primary-400" : "!text-gray-600"}`}
variant='outline'

View File

@@ -6,7 +6,7 @@ import Button from 'src/Components/Button/Button'
import { useAppDispatch, useMediaQuery } from 'src/utils/hooks'
import { PayloadAction } from '@reduxjs/toolkit'
import IconButton from 'src/Components/IconButton/IconButton'
import { useGetFiltersQuery } from 'src/graphql'
import { GetFiltersQuery, useGetFiltersQuery } from 'src/graphql'
import Skeleton from 'react-loading-skeleton';
import { random } from 'src/utils/helperFunctions';
import { MEDIA_QUERIES } from 'src/utils/theme'
@@ -17,14 +17,15 @@ interface Props extends ModalCard {
}
export interface IFormInputs {
text: string,
href: string,
}
type FilterCategory = NonNullable<NonNullable<GetFiltersQuery['categoryList']>[number]>
export type ProjectsFilters = {
categories: { id: string, label: string }[]
categories: FilterCategory[]
tags: { id: string, label: string }[]
yearFounded: typeof yearsFoundedOptions[number]['value'],
projectStatus: typeof projectStatusOptions[number]['value']
@@ -43,7 +44,7 @@ export default function FiltersModal({ onClose, direction, initFilters, callback
const [projectStatusFilter, setProjectStatusFilter] = useState(initFilters?.projectStatus ?? "any");
const [projectLicenseFilter, setProjectLicenseFilter] = useState(initFilters?.projectLicense ?? "any");
const clickCategory = (value: { id: string, label: string }) => {
const clickCategory = (value: FilterCategory) => {
if (categoriesFilter.some(v => v.id === value.id))
setCategoriesFilter([]);
else
@@ -122,8 +123,8 @@ export default function FiltersModal({ onClose, direction, initFilters, callback
active:scale-95 transition-transform
${!categoriesFilter.some(f => f.id === category?.id!) ? "bg-gray-100 hover:bg-gray-200 border-gray-200" : "bg-primary-100 text-primary-600 border-primary-200"}
`}
onClick={() => clickCategory({ id: category?.id!, label: category?.name! })}
>{category?.name}
onClick={() => clickCategory(category!)}
>{category?.icon && <i className={`fa-solid fa-${category?.icon} mr-8 text-gray-700`}></i>} {category?.name}
</button>
</li>)}
{query.loading &&

View File

@@ -3,6 +3,7 @@ query GetFilters {
id
name
icon
projectsCount
}
tags {
id

View File

@@ -1,12 +1,7 @@
import React from 'react'
import { FiArrowLeft } from 'react-icons/fi'
import { MdClose } from 'react-icons/md'
import Skeleton from 'react-loading-skeleton'
import { Link } from 'react-router-dom'
import ASSETS from 'src/assets'
import Badge from 'src/Components/Badge/Badge'
import { Category } from 'src/features/Projects/Components/Categories/Categories'
import { PAGES_ROUTES } from 'src/utils/routing'
import { useProjectsFilters } from '../filters-context'
type Props = {
@@ -23,16 +18,16 @@ export default function Header(props: Props) {
const onSearchPage = !onCategoryPage && !filtersEmpty
const title = onCategoryPage ? `${props.selectedCategry?.projectsCount} projects` :
filtersEmpty ? "Discover 1,592 lightning projects" : "Search results";
const title = onCategoryPage ? `${props.selectedCategry?.name} projects` :
filtersEmpty ? "Discover 1,592 lightning projects" : "All lightning projects";
const subtitle = onCategoryPage ? props.selectedCategry?.name :
const subtitle = onCategoryPage ? "" :
filtersEmpty ? "Explore a directory of lightning startups, projects, and companies"
: ""
return (
<div className='h-[280px] rounded-20 overflow-hidden relative flex flex-col justify-center items-center gap-8'>
<div className='h-[280px] rounded-20 overflow-hidden relative text-center flex flex-col justify-center items-center gap-8'>
<img src="/assets/images/cover.png" alt="" className='absolute inset-0 opacity-20 w-full h-full object-cover z-[-1]' />
{/* <div className='absolute inset-0 w-full h-full bg-gray-300 bg-opacity-50 z-[-1]' /> */}
{/* <Link
@@ -53,11 +48,11 @@ export default function Header(props: Props) {
{!filtersEmpty && <div className=" ">
<p className="text-gray-500 font-medium text-body4 mb-8 mt-8 text-center">filtered by</p>
<div className="flex gap-8 flex-wrap">
{filters?.categories && filters.categories.length > 0 && <Badge size='sm'>Category: <span className='font-bold text-gray-700'>{filters.categories[0].name}</span> <button onClick={() => removeFilter("categories")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.tags && filters.tags.length > 0 && <Badge size='sm'>🏷 <span className='font-bold text-gray-700'>{filters.tags.map(t => t.label).join(', ')}</span> <button onClick={() => removeFilter("tags")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.yearFounded && <Badge size='sm'>📆 Founded in <span className='font-bold text-gray-700'>{filters.yearFounded}</span> <button onClick={() => removeFilter("yearFounded")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.projectStatus && <Badge size='sm'>🌱 Status: <span className='font-bold text-gray-700'>{filters?.projectStatus}</span> <button onClick={() => removeFilter("projectStatus")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.projectLicense && <Badge size='sm'>💻 <span className='font-bold text-gray-700'>{filters.projectLicense}</span> <button onClick={() => removeFilter("projectLicense")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.categories && filters.categories.length > 0 && <Badge size='sm'>Category: <span className='font-bold text-gray-700'>{filters.categories[0].label}</span> <button onClick={() => removeFilter("categories")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.tags && filters.tags.length > 0 && <Badge size='sm'>🏷 <span className='font-bold text-gray-700'>{filters.tags.map(t => t.label).join(', ')}</span> <button onClick={() => removeFilter("tags")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
</div>
</div>}
</div>

View File

@@ -1,5 +1,10 @@
query ExplorePage($filter: JSON, $page: JSON, $pageSize: JSON) {
projects(_filter: $filter, _page: $page, _page_size: $pageSize) {
projects(
_order_by: ["dead", "title"]
_filter: $filter
_page: $page
_page_size: $pageSize
) {
id
title
logo

View File

@@ -411,7 +411,7 @@ export type AllCategoriesQuery = { __typename?: 'Query', categoryList: Array<{ _
export type GetFiltersQueryVariables = Exact<{ [key: string]: never; }>;
export type GetFiltersQuery = { __typename?: 'Query', categoryList: Array<{ __typename?: 'categoryList', id: string | null, name: string | null, icon: string | null } | null> | null, tags: Array<{ __typename?: 'tags', id: string | null, name: string | null, icon: string | null } | null> | null };
export type GetFiltersQuery = { __typename?: 'Query', categoryList: Array<{ __typename?: 'categoryList', id: string | null, name: string | null, icon: string | null, projectsCount: string | null } | null> | null, tags: Array<{ __typename?: 'tags', id: string | null, name: string | null, icon: string | null } | null> | null };
export type ExplorePageQueryVariables = Exact<{
filter: InputMaybe<Scalars['JSON']>;
@@ -475,6 +475,7 @@ export const GetFiltersDocument = gql`
id
name
icon
projectsCount
}
tags {
id
@@ -512,7 +513,12 @@ export type GetFiltersLazyQueryHookResult = ReturnType<typeof useGetFiltersLazyQ
export type GetFiltersQueryResult = Apollo.QueryResult<GetFiltersQuery, GetFiltersQueryVariables>;
export const ExplorePageDocument = gql`
query ExplorePage($filter: JSON, $page: JSON, $pageSize: JSON) {
projects(_filter: $filter, _page: $page, _page_size: $pageSize) {
projects(
_order_by: ["dead", "title"]
_filter: $filter
_page: $page
_page_size: $pageSize
) {
id
title
logo