Skip to content

Commit

Permalink
feat: New Filter UI (No new list view commits) (scraly#1063)
Browse files Browse the repository at this point in the history
* fix(App.css): Zero-ed body margin

* fix(Filters.css): Fixed filters obstructing `YearSelector` center-point

* refactor(ShortDate.jsx): Renamed `short-date` to `shortDate`

* fix(Filter): Fixed panel closing abruptly

* fix(styles/Filters): Fixed panel not on top of map view

* feat(Filters): Added nice looking open/close animation

* feat(Filters): Adjusted UI

* feat(ListView.css): Mobile support

---------

Co-authored-by: Hanz <[email protected]>
  • Loading branch information
HanzCEO and Hanz authored Jun 28, 2024
1 parent eb3f093 commit 9a67227
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 82 deletions.
41 changes: 19 additions & 22 deletions page/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
import {useEffect} from 'react';
import {HashRouter as Router, Routes, Route, useParams, useNavigate, useSearchParams, createSearchParams} from "react-router-dom";

import {CalendarDays, CalendarClock} from 'lucide-react';

import CalendarGrid from 'components/CalendarGrid/CalendarGrid';
import ListView from 'components/ListView/ListView';
import ViewSelector from 'components/ViewSelector/ViewSelector';
import MapView from 'components/MapView/MapView';
import YearSelector from 'components/YearSelector/YearSelector';
import Filters from 'components/Filters/Filters';

import {useHasYearEvents} from 'app.hooks';
import SelectedEvents from 'components/SelectedEvents/SelectedEvents';
import 'misc/fonts/inter/inter.css';
import 'styles/App.css';

Expand All @@ -20,20 +8,29 @@ import { Year } from 'routes/year';
import { DatePage } from 'routes/datepage';
import { MapPage } from 'routes/mappage';
import { ListPage } from 'routes/listpage';
import { FilterContext } from 'contexts/FilterContext';

const App = () => {
// TODO: DRY
const filtercontextdefaults = {
searchParams: {},
open: false
};

return (
<Router>
<h1 className="dcaTitle">Developer Conferences Agenda</h1>
<Routes path="/">
<Route path="" Component={Index} />
<Route path=":year" Component={Year} />
<FilterContext.Provider value={filtercontextdefaults}>
<Router>
<h1 className="dcaTitle">Developer Conferences Agenda</h1>
<Routes path="/">
<Route path="" Component={Index} />
<Route path=":year" Component={Year} />

<Route path=":year/calendar/:month?/:date?" Component={DatePage} />
<Route path="/:year/map" Component={MapPage} />
<Route path="/:year/list" Component={ListPage} />
</Routes>
</Router>
<Route path=":year/calendar/:month?/:date?" Component={DatePage} />
<Route path="/:year/map" Component={MapPage} />
<Route path="/:year/list" Component={ListPage} />
</Routes>
</Router>
</FilterContext.Provider>
);
};

Expand Down
56 changes: 31 additions & 25 deletions page/src/components/Filters/Filters.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import React, { useState, useCallback } from 'react';
import React, { useState, useCallback, useContext, useEffect } from 'react';
import {useSearchParams} from "react-router-dom";

import { Filter, FilterX } from 'lucide-react';

import {useCountries} from 'app.hooks';

import 'styles/Filters.css';
import { FilterContext } from 'contexts/FilterContext';

const Filters = () => {
const [searchParams, setSearchParams] = useSearchParams();
const [open, setOpen] = useState(searchParams.size > 0);
const context = useContext(FilterContext);
console.log(context)
const [searchParams, setSearchParams] = useSearchParams(context.searchParams);
const [open, setOpen] = useState(context.open);

useEffect(() => {
context.searchParams = searchParams;
context.open = open;
}, [searchParams, open]);

const onChange = useCallback((key, value) => {
setSearchParams({...Object.fromEntries(searchParams), [key]: value})
Expand All @@ -26,40 +34,38 @@ const Filters = () => {
title={open ? 'Close filters' : 'Open filters'}
onClick={() => {
if (open) {
setSearchParams({})
// setSearchParams({});
setOpen(false);
return;
}
setOpen(true);
}}
>
{open ? <FilterX/> : <Filter/>}
<div className='filters-icon'>{open ? <FilterX size={'32px'}/> : <Filter size={'32px'}/>}</div>
<span className='filters-title'>Filters</span>
</div>

<div className='filtersItem'>
<label htmlFor='filter-query'>Search:</label>
<input id='filter-query' type='text' value={search.query} onChange={(e) => onChange('query', e.target.value)}/>
</div>

<div className='filtersItem'>
<label htmlFor='filter-call-for-papers'>Call For Papers Open:</label>
<input checked={search.callForPapers == 'true'} type='checkbox' id='filter-call-for-papers' onChange={(e) => onChange('callForPapers', e.target.checked)}/>
<input id='filter-query' type='text' value={search.query} onChange={(e) => onChange('query', e.target.value)} placeholder="Search..."/>
</div>

<div className='filtersItem'>
<label htmlFor='filter-closed-captions'>Closed Captions:</label>
<input checked={search.closedCaptions == 'true'} type='checkbox' id='filter-closed-captions' onChange={(e) => onChange('closedCaptions', e.target.checked)}/>
</div>

<div className='filtersItem'>
<label htmlFor='filter-scholarship'>Scholarship:</label>
<input checked={search.scholarship == 'true'} type='checkbox' id='filter-scholarship' onChange={(e) => onChange('scholarship', e.target.checked)}/>
</div>

<div className='filtersItem'>
<label htmlFor='filter-online'>Online:</label>
<input checked={search.online == 'true'} type='checkbox' id='filter-online' onChange={(e) => onChange('online', e.target.checked)}/>
<div className='filtersList'>
<div className='filtersItem'>
<input checked={search.callForPapers == 'true'} type='checkbox' id='filter-call-for-papers' onChange={(e) => onChange('callForPapers', e.target.checked)}/>
<label htmlFor='filter-call-for-papers'>Call For Papers Open</label>
</div>
<div className='filtersItem'>
<input checked={search.closedCaptions == 'true'} type='checkbox' id='filter-closed-captions' onChange={(e) => onChange('closedCaptions', e.target.checked)}/>
<label htmlFor='filter-closed-captions'>Closed Captions</label>
</div>
<div className='filtersItem'>
<input checked={search.scholarship == 'true'} type='checkbox' id='filter-scholarship' onChange={(e) => onChange('scholarship', e.target.checked)}/>
<label htmlFor='filter-scholarship'>Scholarship</label>
</div>
<div className='filtersItem'>
<input checked={search.online == 'true'} type='checkbox' id='filter-online' onChange={(e) => onChange('online', e.target.checked)}/>
<label htmlFor='filter-online'>Online</label>
</div>
</div>

<div className='filtersItem'>
Expand Down
2 changes: 1 addition & 1 deletion page/src/components/ShortDate/ShortDate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const ShortDate = ({dates}) => {
</span>
);
}
return <span className='short-date'>{startDate}</span>;
return <span className='shortDate'>{startDate}</span>;
};

export default ShortDate;
3 changes: 3 additions & 0 deletions page/src/components/ViewSelector/ViewSelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,17 @@ const ViewSelector = ({selected}) => {
<Calendar
className={selected === 'calendar' ? 'view-selector calendar-view selected' : 'view-selector calendar-view'}
onClick={() => navigate(`/${year}/calendar?${createSearchParams(searchParams)}`)}
size={'32px'}
/>
<List
className={selected === 'list' ? 'view-selector list-view selected' : 'view-selector list-view'}
onClick={() => navigate(`/${year}/list?${createSearchParams(searchParams)}`)}
size={'32px'}
/>
<Map
className={selected === 'map' ? 'view-selector map-view selected' : 'view-selector map-view'}
onClick={() => navigate(`/${year}/map?${createSearchParams(searchParams)}`)}
size={'32px'}
/>
</div>
);
Expand Down
6 changes: 6 additions & 0 deletions page/src/contexts/FilterContext.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createContext } from "react";

export const FilterContext = createContext({
searchParams: {},
open: false
});
17 changes: 17 additions & 0 deletions page/src/styles/App.css
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
body {
outline: 0;
box-sizing: border-box;
margin: 0;

font-family: Inter, Arial, sans-serif;
flex-grow: 1;
}

body * {
box-sizing: border-box;
outline: 0;
}

.dcaTitle {
text-align: center;
}

.dcaGrid {
display: flex;
position: relative;
}

.dcaContent {
Expand Down Expand Up @@ -75,3 +82,13 @@ body > footer > .content {
.footer {
color: inherit;
}

input, select {
font-family: inherit;
border-radius: 3px;
border: 0;
}

input[type=text] {
border: solid 1px #aaa;
}
69 changes: 35 additions & 34 deletions page/src/styles/Filters.css
Original file line number Diff line number Diff line change
@@ -1,89 +1,90 @@
.filters {
border-right: 1px solid #ccc;
padding: 10px;
padding-right: 20px;
transition: min-width 1s, width 1s, border-color 1s;
padding: 1rem 2rem;
transition: 1s;
position: fixed;
padding-top: 7rem;
top: 0;
left: 0;
z-index: 999999;
background: white;
height: 100%;
}

.filters-icon {
position: fixed;
/* top: 7rem; */
left: 100%;
}

.filters-header {
white-space: nowrap;
display: flex;
align-items: center;
cursor: pointer;
margin-bottom: 5px;
margin-bottom: 1rem;
}

.filters .lucide-filter, .filters .lucide-filter-x {
opacity: 1;
min-width: 24px;
background: #eee;
padding: 5px;
border-radius: 3px;
border-radius: 0 3px 3px 0;
border: 1px solid #ccc;
}

.filters .filters-title {
font-weight: 600;
font-size: 24px;
margin-left: 5px;
}

.filters.open .filters-title {
opacity: 1;
transition: opacity 1s;
}

.filters.closed .filters-title {
opacity: 0;
transition: opacity 1s;
background: revert;
}

.filters.open {
min-width: 210px;
width: 210px;
transform: translateX(0%);
border-color: #cccccc;
}

.filters.closed {
width: 0;
min-width: 10px;
transform: translateX(-100%);
border-color: #cccccc00;
}

.filters.closed .filtersItem {
opacity: 0;
transition: opacity 1s;
}

.filters.open .filtersItem {
opacity: 1;
transition: opacity 1s;
.filtersList {
display: flex;
flex-direction: column;
gap: 0.75rem;
margin: 2rem 0;
}

.filters .filtersItem {
margin-bottom: 20px;
overflow: hidden;
white-space: nowrap;
}

.filters .filtersItem input[type=checkbox] {
margin-right: 0.5rem;
}

.filters .filtersItem input[type=text] {
padding: 10px;
max-width: 180px;
display: block;
padding: 0.5rem 1rem;
width: 100%;
}

.filters .filtersItem label {
font-weight: 600;
margin-bottom: 10px;
display: inline-block;
width: 100%;
}

.filters .filtersItem label[for=filter-query] {
display: block;
}

.filters .filtersItem select {
padding: 10px;
max-width: 180px;
padding: 0.5rem 1rem;
width: 100%;
display: block;
background: transparent;
margin-top: 10px;
Expand Down
Loading

0 comments on commit 9a67227

Please sign in to comment.