Skip to content

Commit

Permalink
Improve events and load more list'
Browse files Browse the repository at this point in the history
  • Loading branch information
pookmish committed Jan 1, 2024
1 parent 3e20e6d commit 3c48803
Show file tree
Hide file tree
Showing 12 changed files with 63 additions and 143 deletions.
56 changes: 28 additions & 28 deletions src/components/elements/load-more-list.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,59 @@
"use client";

import {
JSX,
ComponentProps,
RefObject,
useLayoutEffect,
useRef,
useState,
HtmlHTMLAttributes
} from "react";
import {useLayoutEffect, useRef, HtmlHTMLAttributes, JSX, useId} from "react";
import Button from "@components/elements/button";
import {useAutoAnimate} from "@formkit/auto-animate/react";
import {Maybe} from "@lib/gql/__generated__/drupal";
import {useBoolean, useCounter} from "usehooks-ts";

type Props = HtmlHTMLAttributes<HTMLDivElement> & {
buttonText?: Maybe<string> | JSX.Element
children: JSX.Element[],
listProps?: ComponentProps<any>
itemProps?: ComponentProps<any>,
buttonText?: string | JSX.Element
ulProps?: HtmlHTMLAttributes<HTMLUListElement>
liProps?: HtmlHTMLAttributes<HTMLLIElement>,
itemsPerPage?: number
}

const LoadMoreList = ({buttonText, children, listProps, itemProps, itemsPerPage = 20, ...props}: Props) => {
const [shownItems, setShownItems] = useState<number>(itemsPerPage)
const [allowFocus, setAllowFocus] = useState<boolean>(false);
const ref: RefObject<HTMLLIElement> = useRef<HTMLLIElement | null>(null);
const LoadMoreList = ({buttonText, children, ulProps, liProps, itemsPerPage = 20, ...props}: Props) => {
const id = useId();
const {count: shownItems, setCount: setShownItems} = useCounter(itemsPerPage)
const {value: focusOnElement, setTrue: enableFocusElement, setFalse: disableFocusElement} = useBoolean(false)

const ref = useRef<HTMLLIElement>(null);
const [animationParent] = useAutoAnimate();

const showMoreItems = () => {
setAllowFocus(true);
enableFocusElement();
setShownItems(shownItems + itemsPerPage);
}

useLayoutEffect(() => ref.current?.focus(), [shownItems]);

const focusingItem = shownItems - itemsPerPage;

const items = typeof children === 'string'? [children]: children;
const items = Array.isArray(children) ? children : [children]
const itemsToShow = items.slice(0, shownItems);
return (
<div {...props}>
<ul {...listProps} ref={animationParent}>
<ul {...ulProps} ref={animationParent}>

{items.slice(0, shownItems).map((item, i) =>
{itemsToShow.map((item, i) =>
<li
key={i}
key={`${id}--${i}`}
ref={focusingItem === i ? ref : null}
tabIndex={focusingItem === i && allowFocus ? 0 : undefined}
onBlur={() => setAllowFocus(false)}
{...itemProps}
tabIndex={focusingItem === i && focusOnElement ? 0 : undefined}
onBlur={disableFocusElement}
{...liProps}
>
{item}
</li>
)}
</ul>
{children.length > shownItems &&

{items.length > itemsPerPage &&
<span className="sar-only" aria-live="polite">
Showing {itemsToShow.length} of {items.length} total items.
</span>
}

{items.length > shownItems &&
<Button centered onClick={showMoreItems}>
{buttonText ? buttonText : "Load More"}
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ const StanfordEventCard = ({node, headingLevel, ...props}: Props) => {
</Heading>


<div className="flex items-center gap-5">
<time className="flex items-center gap-5" dateTime={start.toISOString()}>
<CalendarDaysIcon width={30} className="shrink-0"/>
{dateTimeString}
</div>
</time>

{node.suEventAltLoc &&
<div className="flex items-center gap-5">
Expand Down Expand Up @@ -113,7 +113,13 @@ export const getEventTimeString = (start: Date, end: Date, timezone: string): st
endHour === 23 &&
endMinute === 59
) {
return 'All Day';
return start.toLocaleDateString('en-us', {
weekday: "long",
month: "long",
day: "numeric",
year: "numeric",
timeZone: timezone
});
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Address from "@components/elements/address";
import {H2, H3} from "@components/elements/headers";
import {HtmlHTMLAttributes} from "react";
import {NodeStanfordEvent} from "@lib/gql/__generated__/drupal";
import {getEventTimeString} from "@components/nodes/cards/stanford-event/stanford-event-card";

type Props = HtmlHTMLAttributes<HTMLDivElement> & {
node: NodeStanfordEvent
Expand Down Expand Up @@ -56,10 +57,10 @@ const StanfordEventListItem = ({node, headingLevel, ...props}: Props) => {
</div>
}

<div className="flex items-center gap-5 mb-5">
<time className="flex items-center gap-5 mb-5" dateTime={start.toISOString()}>
<CalendarDaysIcon width={30} className="shrink-0"/>
{dateTimeString}
</div>
</time>

{node.suEventLocation &&
<div>
Expand All @@ -81,95 +82,4 @@ const StanfordEventListItem = ({node, headingLevel, ...props}: Props) => {
)
}


export const getEventTimeString = (start: Date, end: Date, timezone: string): string => {
const startHour = parseInt(start.toLocaleTimeString("en-US", {
hour: "numeric",
hour12: false,
timeZone: timezone
}))
const startMinute = parseInt(start.toLocaleTimeString("en-US", {
minute: "numeric",
hour12: false,
timeZone: timezone
}))

const endHour = parseInt(end.toLocaleTimeString("en-US", {
hour: "numeric",
hour12: false,
timeZone: timezone
}))
const endMinute = parseInt(end.toLocaleTimeString("en-US", {
minute: "numeric",
hour12: false,
timeZone: timezone
}))

let dateTimeString: string;

// Multiple days.
if (start.toLocaleDateString("en-US", {timeZone: 'America/Los_Angeles'}) != end.toLocaleDateString("en-US", {timeZone: 'America/Los_Angeles'})) {
dateTimeString = start.toLocaleDateString("en-US", {
month: "long",
day: "numeric",
year: "numeric",
timeZone: timezone
}) + ' - ' + end.toLocaleDateString("en-US", {
month: "long",
day: "numeric",
year: "numeric",
timeZone: timezone
})
return dateTimeString;
}

// All Day display.
if (
(startHour === 24 || startHour === 0) &&
startMinute === 0 &&
endHour === 23 &&
endMinute === 59
) {
return start.toLocaleDateString('en-us', {
weekday: "long",
month: "long",
day: "numeric",
year: "numeric",
timeZone: timezone
});
}


// Different start and end times.
if (startHour !== endHour || startMinute !== endMinute) {
dateTimeString = start.toLocaleDateString('en-US', {
weekday: "long",
month: "long",
day: "numeric",
year: "numeric",
timeZone: timezone
});
dateTimeString += " | " + start.toLocaleTimeString("en-US", {
hour: "numeric",
minute: "numeric",
timeZone: timezone
});
dateTimeString += ' - ';
dateTimeString += end.toLocaleTimeString("en-US", {
hour: "numeric",
minute: "numeric",
timeZoneName: "short",
timeZone: timezone
})
return dateTimeString;
}

// Start and end times are the same, just display the start time.
return start.toLocaleTimeString("en-US", {
hour: "numeric",
minute: "numeric",
timeZoneName: "short",
timeZone: timezone
})
}
export default StanfordEventListItem;
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ const StanfordEventPage = ({node, ...props}: Props) => {
<div className="border border-black-40 py-20 px-10 lg:px-48 lg:w-3/4 mx-auto mb-32">
<H2 className="text-m2">Event Details:</H2>
<div className="grid items-start lg:grid-cols-2 gap-20">
<div className="flex items-center gap-5">
<time className="flex items-center gap-5" dateTime={startTime.toISOString()}>
<CalendarDaysIcon width={30} className="shrink-0"/>
{getEventTimeString(startTime, endTime, timezone)}
</div>
</time>


{(node.suEventEmail || node.suEventTelephone) &&
Expand Down
10 changes: 7 additions & 3 deletions src/components/nodes/pages/stanford-news/stanford-news-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ const StanfordNewsPage = ({node, ...props}: Props) => {
month: "long",
day: "numeric",
year: "numeric"
}) : null;
}) : undefined;

let bannerImageUrl: string | undefined, bannerImageAlt: string = ""
if (node.suNewsBanner?.__typename === 'MediaImage') {
bannerImageUrl = node.suNewsBanner.mediaImage.url
bannerImageAlt = node.suNewsBanner.mediaImage.alt || "";
}

const topics = (node.suNewsTopics && node.suNewsTopics.length > 0) ? node.suNewsTopics.slice(0, 3) : undefined;
const topics = node.suNewsTopics?.slice(0, 3);

return (
<article className="centered mt-32" {...props}>
Expand All @@ -51,7 +51,11 @@ const StanfordNewsPage = ({node, ...props}: Props) => {
{node.suNewsDek && <div className="mb-10">{node.suNewsDek}</div>}

<div className="flex gap-5 items-center">
{publishDate && <div>{publishDate}</div>}
{node.suNewsPublishingDate &&
<time dateTime={new Date(node.suNewsPublishingDate.time).toISOString().substring(0, 10)}>
{publishDate}
</time>
}
{node.suNewsByline && <div>{node.suNewsByline}</div>}

{!node.suNewsHideSocial &&
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/card-view-grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {NodeUnion} from "@lib/gql/__generated__/drupal";
const CardViewGrid = ({items, headingLevel}: { items: NodeUnion[], headingLevel: string }) => {
return (
<LoadMoreList
listProps={{className: "list-unstyled grid 3xl:grid-cols-3 gap-20"}}
itemProps={{className: ""}}
ulProps={{className: "list-unstyled grid 3xl:grid-cols-3 gap-20"}}
liProps={{className: ""}}
>
{items.map(item =>
<NodeCard node={item} key={item.id} headingLevel={headingLevel}/>
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/stanford-courses/course-list-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ const CourseListView = async ({items = [], emptyMessage, headingLevel}: Props) =
return (
<LoadMoreList
buttonText={<>Load More<span className="sr-only">&nbsp;courses</span></>}
listProps={{className: "list-unstyled mb-20"}}
itemProps={{className: "border-b border-black-20 last-of-type:border-0 pb-10 last:pb-0 pt-10 first:pt-0"}}
ulProps={{className: "list-unstyled mb-20"}}
liProps={{className: "border-b border-black-20 last-of-type:border-0 pb-10 last:pb-0 pt-10 first:pt-0"}}
>
{items.map(item =>
<StanfordCourseListItem key={item.id} node={item} headingLevel={headingLevel}/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ const EventsFilteredListView = ({items, topics}: { items: NodeStanfordEvent[], t
<LoadMoreList
key={displayedEvents.map(event => event.id).join(',')}
buttonText={<>Load More<span className="sr-only">&nbsp;Events</span></>}
listProps={{className: "list-unstyled mb-20"}}
itemProps={{className: "border-b border-black-20 last-of-type:border-0 pb-10 last:pb-0 pt-10 first:pt-0"}}
ulProps={{className: "list-unstyled mb-20"}}
liProps={{className: "border-b border-black-20 last-of-type:border-0 pb-10 last:pb-0 pt-10 first:pt-0"}}
itemsPerPage={3}
>
{displayedEvents.map(event => <StanfordEventListItem key={event.id} node={event}/>)}
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/stanford-events/events-list-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ const EventsListView = async ({items = [], emptyMessage, headingLevel}: Props) =
return (
<LoadMoreList
buttonText={<>Load More<span className="sr-only">&nbsp;Events</span></>}
listProps={{className: "list-unstyled mb-20"}}
itemProps={{className: "border-b border-black-20 last-of-type:border-0 pb-10 last:pb-0 pt-10 first:pt-0"}}
ulProps={{className: "list-unstyled mb-20"}}
liProps={{className: "border-b border-black-20 last-of-type:border-0 pb-10 last:pb-0 pt-10 first:pt-0"}}
>
{items.map(item =>
<StanfordEventListItem key={item.id} node={item} headingLevel={headingLevel}/>
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/stanford-news/news-list-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ const NewsListView = async ({items = [], emptyMessage, headingLevel}: Props) =>
return (
<LoadMoreList
buttonText={<>Load More<span className="sr-only">&nbsp;news</span></>}
listProps={{className: "list-unstyled mb-20"}}
itemProps={{className: "border-b border-black-20 last-of-type:border-0 pb-10 last:pb-0 pt-10 first:pt-0"}}
ulProps={{className: "list-unstyled mb-20"}}
liProps={{className: "border-b border-black-20 last-of-type:border-0 pb-10 last:pb-0 pt-10 first:pt-0"}}
>
{items.map(item =>
<StanfordNewsListItem key={item.id} node={item} headingLevel={headingLevel}/>
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/stanford-page/page-list-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ const PageListView = async ({emptyMessage, items = [], headingLevel}: Props) =>
}
return (
<LoadMoreList
listProps={{className: "list-unstyled mb-20"}}
itemProps={{className: "border-b border-black-20 last-of-type:border-0 pb-10 last:pb-0 pt-10 first:pt-0"}}
ulProps={{className: "list-unstyled mb-20"}}
liProps={{className: "border-b border-black-20 last-of-type:border-0 pb-10 last:pb-0 pt-10 first:pt-0"}}
>
{items.map(item =>
<StanfordPageListItem key={item.id} node={item} headingLevel={headingLevel}/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ const PublicationsChicagoView = async ({items = [], emptyMessage, headingLevel}:
}
return (
<LoadMoreList
listProps={{className: "list-unstyled mb-20"}}
itemProps={{className: "border-b border-black-20 last-of-type:border-0 pb-10 last:pb-0 pt-10 first:pt-0"}}
ulProps={{className: "list-unstyled mb-20"}}
liProps={{className: "border-b border-black-20 last-of-type:border-0 pb-10 last:pb-0 pt-10 first:pt-0"}}
>
{items.map(item =>
<StanfordPublicationListItem key={item.id} node={item} headingLevel={headingLevel}/>
Expand Down

0 comments on commit 3c48803

Please sign in to comment.