on master help sign in
events: selectable, two-up layout
7f38eb1Matilde Park
pages/events.js+87−39
@@ -1,23 +1,24 @@
1import Head from "next/head";
1import Head from "next/head";
2−import Link from "next/link";
2+import cn from "classnames";
3import { DateTime } from "luxon";
3import { DateTime } from "luxon";
4−
4+import { useState } from "react";
5import Meta from "../components/Meta";
5import Meta from "../components/Meta";
6import {
6import {
7 Container,
7 Container,
8 SingleColumn,
8 SingleColumn,
9 Section,
9 Section,
10 IntraNav,
10 IntraNav,
11+ TwoUp,
11} from "@urbit/foundation-design-system";
12} from "@urbit/foundation-design-system";
12import Footer from "../components/Footer";
13import Footer from "../components/Footer";
13import Header from "../components/Header";
14import Header from "../components/Header";
14import EventPreview from "../components/EventPreview";
15import EventPreview from "../components/EventPreview";
15−import { contact } from "../lib/constants";
16−import { getAllEvents, generateRealtimeDate } from "../lib/lib";
16+import { getAllEvents, generateRealtimeDate, pair } from "../lib/lib";
17
17
18import { eventKeys } from "../lib/constants";
18import { eventKeys } from "../lib/constants";
19
19
20export default function Events({ events, search }) {
20export default function Events({ events, search }) {
21+ const [selected, setSelected] = useState("All");
21 const post = {
22 const post = {
22 title: "Events",
23 title: "Events",
23 description: "In-person, remote, and recorded events about Urbit.",
24 description: "In-person, remote, and recorded events about Urbit.",
@@ -25,32 +26,63 @@ export default function Events({ events, search }) {
25
26
26 const now = DateTime.now();
27 const now = DateTime.now();
27
28
29+ const selectionFilter = (event) => {
30+ if (selected === "All") {
31+ return true;
32+ } else if (selected === "In-person") {
33+ return event.location !== "Online Event";
34+ } else if (selected === "Online") {
35+ return event.location === "Online Event";
36+ }
37+ };
38+
39+ const pastEvents = pair(
28− const pastEvents = events.filter((event) => {
40+ events.filter(selectionFilter).filter((event) => {
29− const ends = generateRealtimeDate(event.ends);
41+ const ends = generateRealtimeDate(event.ends);
30− return ends < now;
42+ return ends < now;
31− });
43+ })
44+ );
32
45
33− const futureEvents = events
46+ const futureEvents = pair(
47+ events
48+ .filter(selectionFilter)
49+ .filter((event) => {
50+ const starts = generateRealtimeDate(event.starts);
51+ return starts > now;
52+ })
53+ .sort((a, b) => {
54+ const aStarts = generateRealtimeDate(a.starts).ts;
55+ const bStarts = generateRealtimeDate(b.starts).ts;
56+ if (aStarts > bStarts) {
57+ return 1;
58+ } else if (aStarts === bStarts) {
59+ return 0;
60+ }
61+ return -1;
62+ })
63+ );
64+
65+ const happeningNow = pair(
34− .filter((event) => {
66+ events.filter(selectionFilter).filter((event) => {
35 const starts = generateRealtimeDate(event.starts);
67 const starts = generateRealtimeDate(event.starts);
68+ const ends = generateRealtimeDate(event.ends);
36− return starts > now;
69+ return starts < DateTime.now() && ends > now;
37 })
70 })
38− .sort((a, b) => {
39− const aStarts = generateRealtimeDate(a.starts).ts;
40− const bStarts = generateRealtimeDate(b.starts).ts;
41− if (aStarts > bStarts) {
42− return 1;
43− } else if (aStarts === bStarts) {
44− return 0;
45− }
46− return -1;
47− });
71+ );
48
72
49− const happeningNow = events.filter((event) => {
73+ const SelectedButton = ({ selection, text }) => {
50− const starts = generateRealtimeDate(event.starts);
74+ return (
51− const ends = generateRealtimeDate(event.ends);
75+ <a
52− return starts < DateTime.now() && ends > now;
76+ className={cn("badge-lg w-fit cursor-pointer type-ui", {
77+ "bg-wall-600 text-white": selected === selection,
78+ "bg-wall-100 text-wall-500": selected !== selection,
79+ })}
80+ onClick={() => setSelected(selection)}
81+ >
82+ {text}
83+ </a>
84+ );
53− });
85+ };
54
86
55 return (
87 return (
56 <Container>
88 <Container>
@@ -64,13 +96,11 @@ export default function Events({ events, search }) {
64 <Section narrow>
96 <Section narrow>
65 <div className="measure">
97 <div className="measure">
66 <h1 className="pb-16">Events</h1>
98 <h1 className="pb-16">Events</h1>
67− <p className="pb-6">
99+ <div className="flex space-x-2">
68− Events of all kinds: In-person, Remote, and Recorded.
100+ <SelectedButton selection="All" text="All Events" />
69− </p>
101+ <SelectedButton selection="In-person" text="In-person" />
70− <p>
102+ <SelectedButton selection="Online" text="Online" />
71− <a href={contact.newsletter}>Subscribe</a> to the Urbit Newsletter
103+ </div>
72− for regular updates, including new blog posts and events.
73− </p>
74 </div>
104 </div>
75 </Section>
105 </Section>
76
106
@@ -80,8 +110,14 @@ export default function Events({ events, search }) {
80 <div className="mb-8 mt-16 table">
110 <div className="mb-8 mt-16 table">
81 <h3 className="text-green-400">Happening Now</h3>
111 <h3 className="text-green-400">Happening Now</h3>
82 </div>
112 </div>
83− {happeningNow.map((post) => {
113+ {happeningNow.map((group) => {
114+ return (
115+ <TwoUp>
116+ {group.map((post) => (
84− return <EventPreview big event={post} className="mb-8" />;
117+ <EventPreview big event={post} className="mb-8" />
118+ ))}
119+ </TwoUp>
120+ );
85 })}
121 })}
86 </>
122 </>
87 ) : null}
123 ) : null}
@@ -90,8 +126,14 @@ export default function Events({ events, search }) {
90 <div className="mb-8 mt-16 table">
126 <div className="mb-8 mt-16 table">
91 <h3 className="">Coming Soon</h3>
127 <h3 className="">Coming Soon</h3>
92 </div>
128 </div>
93− {futureEvents.map((post) => {
129+ {futureEvents.map((group) => {
130+ return (
131+ <TwoUp>
132+ {group.map((post) => (
94− return <EventPreview big event={post} className="mb-8" />;
133+ <EventPreview event={post} className="mb-8" />
134+ ))}
135+ </TwoUp>
136+ );
95 })}
137 })}
96 </>
138 </>
97 ) : null}
139 ) : null}
@@ -99,8 +141,14 @@ export default function Events({ events, search }) {
99 <h3 className="text-wall-500">Past Events</h3>
141 <h3 className="text-wall-500">Past Events</h3>
100 </div>
142 </div>
101
143
102− {pastEvents.map((post) => {
144+ {pastEvents.map((group) => {
145+ return (
146+ <TwoUp>
147+ {group.map((post) => (
103− return <EventPreview big event={post} className="mb-8" />;
148+ <EventPreview event={post} className="mb-8" />
149+ ))}
150+ </TwoUp>
151+ );
104 })}
152 })}
105 </Section>
153 </Section>
106 </SingleColumn>
154 </SingleColumn>