tidy up event filters a lil bit, add toggle function

This commit is contained in:
elisejakob
2024-06-20 21:44:37 +02:00
parent 9b3eb3c4a6
commit d5fa2ddf61
6 changed files with 145 additions and 63 deletions

View File

@ -16,6 +16,8 @@ import styles from "./eventContainer.module.scss";
import { formatDate, formatYearMonth } from "@/lib/date"; import { formatDate, formatYearMonth } from "@/lib/date";
import { parse } from "date-fns"; import { parse } from "date-fns";
import { unique } from "@/lib/common"; import { unique } from "@/lib/common";
import Icon from "../general/Icon";
import { useState } from "react";
/* /*
TODO: canonical / alternate URLs https://github.com/47ng/nuqs?tab=readme-ov-file#seo TODO: canonical / alternate URLs https://github.com/47ng/nuqs?tab=readme-ov-file#seo
@ -64,22 +66,40 @@ export const EventContainer = ({
.includes(category) .includes(category)
); );
const [showFilter, setShowFilter] = useState(false);
function toggleFilter() {
setShowFilter(!showFilter);
}
return ( return (
<div className={styles.events}> <div className={styles.events}>
<EventFilter
eventCategories={filterableCategories}
setCategory={setCategory}
activeCategory={category}
eventOrganizers={filterableOrganizers}
setOrganizer={setOrganizer}
activeOrganizer={organizer}
/>
<div className={styles.eventWrapper}> <div className={styles.eventWrapper}>
<div className={styles.displayOptions}> <div className={styles.displayOptions}>
<button onClick={() => setMode(null)}>Vis liste</button> <button onClick={() => setMode(null)} className="button secondary">
<button onClick={() => setMode("calendar")}>Vis kalender</button> <span>Vis liste</span>
<button>Filtrer</button> <Icon />
</button>
<button
onClick={() => setMode("calendar")}
className="button secondary"
>
<span>Vis kalender</span>
<Icon />
</button>
<button onClick={toggleFilter} className="button tertiary">
<span>Filter</span>
<Icon />
</button>
</div> </div>
<EventFilter
eventCategories={filterableCategories}
setCategory={setCategory}
activeCategory={category}
eventOrganizers={filterableOrganizers}
setOrganizer={setOrganizer}
activeOrganizer={organizer}
isVisible={showFilter}
/>
{mode === "list" && <EventList events={filteredEvents} />} {mode === "list" && <EventList events={filteredEvents} />}
{mode === "calendar" && <EventCalendar events={filteredEvents} />} {mode === "calendar" && <EventCalendar events={filteredEvents} />}
</div> </div>

View File

@ -9,6 +9,7 @@ export const EventFilter = ({
eventOrganizers, eventOrganizers,
setOrganizer, setOrganizer,
activeOrganizer, activeOrganizer,
isVisible,
}: { }: {
eventCategories: EventCategory[]; eventCategories: EventCategory[];
setCategory: (slug: string | null) => void; setCategory: (slug: string | null) => void;
@ -16,6 +17,7 @@ export const EventFilter = ({
eventOrganizers: EventOrganizer[]; eventOrganizers: EventOrganizer[];
setOrganizer: (slug: string | null) => void; setOrganizer: (slug: string | null) => void;
activeOrganizer: string | null; activeOrganizer: string | null;
isVisible: boolean;
}) => { }) => {
const onOrganizerSelect = (e: React.ChangeEvent<HTMLSelectElement>) => { const onOrganizerSelect = (e: React.ChangeEvent<HTMLSelectElement>) => {
const organizer = e.target.value; const organizer = e.target.value;
@ -23,44 +25,52 @@ export const EventFilter = ({
}; };
return ( return (
<div className={styles.eventFilter}> <div className={styles.eventFilter} data-show={isVisible}>
<span className="suphead">Kategori</span> <div className={styles.filterContent}>
<ul> <div className={styles.filterItem}>
{eventCategories <span className={`suphead ${styles.heading}`}>Kategori</span>
.filter((x) => x.showInFilters) <ul>
.map((category) => ( {eventCategories
<li .filter((x) => x.showInFilters)
key={category.slug} .map((category) => (
className={activeCategory === category.slug ? styles.active : ""} <li
key={category.slug}
className={
activeCategory === category.slug ? styles.active : ""
}
>
<button
onClick={() =>
setCategory(
activeCategory === category.slug ? null : category.slug
)
}
>
{category.name}
</button>
</li>
))}
</ul>
</div>
<div className={styles.filterItem}>
<label htmlFor="organizer" className={`suphead ${styles.heading}`}>
Arrangør
</label>
<div>
<select
name="organizer"
value={activeOrganizer ?? ""}
onChange={onOrganizerSelect}
> >
<button <option value="">Vis alle</option>
onClick={() => {eventOrganizers.map((organizer) => (
setCategory( <option key={organizer.slug} value={organizer.slug}>
activeCategory === category.slug ? null : category.slug {organizer.name}
) </option>
} ))}
> </select>
{category.name} </div>
</button> </div>
</li>
))}
</ul>
<label htmlFor="organizer" className="suphead">
Arrangør
</label>
<div>
<select
name="organizer"
value={activeOrganizer ?? ""}
onChange={onOrganizerSelect}
>
<option value="">Vis alle</option>
{eventOrganizers.map((organizer) => (
<option key={organizer.slug} value={organizer.slug}>
{organizer.name}
</option>
))}
</select>
</div> </div>
</div> </div>
); );

View File

@ -12,15 +12,19 @@
} }
.displayOptions { .displayOptions {
display: grid; display: flex;
grid-template-columns: repeat(3, 1fr); gap: .5rem;
gap: var(--spacing-gap-column); align-items: center;
//padding: 0 var(--spacing-sitepadding); position: relative;
z-index: 10;
transition: background-color .5s ease;
button { button:last-child {
border-radius: 0; margin: 0 0 0 auto;
background: var(--color-deepBrick); }
color: var(--color-goldenBeige);
&[data-showFilter=true] {
background-color: var(--color-background-secondary);
} }
} }
@ -91,6 +95,10 @@
} }
@media (max-width: 1200px) { @media (max-width: 1200px) {
.eventList {
grid-template-columns: 1fr 1fr;
}
.calendarWeek { .calendarWeek {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
@ -117,3 +125,9 @@
} }
} }
} }
@media (max-width: 700px) {
.eventList {
grid-template-columns: 1fr;
}
}

View File

@ -1,10 +1,26 @@
.eventFilter { .eventFilter {
display: flex; display: grid;
align-items: center; grid-template-rows: 0fr;
gap: 1rem; transition: grid-template-rows .5s ease;
background: var(--color-background-secondary); margin: var(--spacing-sitepadding) calc(var(--spacing-sitepadding)*-1) 0;
margin: var(--spacing-sitepadding) calc(var(--spacing-sitepadding)*-1);
padding: 1rem var(--spacing-sitepadding); .filterContent {
background-color: var(--color-background);
padding: 1rem var(--spacing-sitepadding);
min-height: 0;
visibility: hidden;
opacity: 0;
transition: visibility .5s, opacity .5s ease, background-color .5s ease;
}
.filterItem {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
}
ul { ul {
list-style: none; list-style: none;
@ -25,4 +41,14 @@
color: var(--color-goldenBeige); color: var(--color-goldenBeige);
} }
} }
&[data-show=true] {
grid-template-rows: 1fr;
.filterContent {
background-color: var(--color-background-secondary);
visibility: visible;
opacity: 1;
}
}
} }

View File

@ -1,6 +1,6 @@
.pageHeader { .pageHeader {
position: relative; position: relative;
padding: var(--spacing-l) 0 calc(var(--spacing-l) + var(--spacing-sitepadding)); padding: var(--spacing-l) 0 var(--spacing-sitepadding);
} }
.title { .title {

View File

@ -145,6 +145,18 @@ input[type="text"] {
transition: opacity var(--transition-easing); transition: opacity var(--transition-easing);
} }
select {
border-radius: 10rem;
background: var(--color-white);
color: var(--color-text);
border: 2px solid currentColor;
padding: .5rem 1rem;
font-family: inherit;
font-size: var(--font-size-body);
font-weight: 500;
transition: opacity var(--transition-easing);
}
.number { .number {
font-family: var(--font-serif); font-family: var(--font-serif);
font-weight: 400; font-weight: 400;