Skip to content

Commit

Permalink
Merge branch '1.x' into invalidate-404-pages
Browse files Browse the repository at this point in the history
  • Loading branch information
imonroe authored Jan 7, 2025
2 parents 9c2159b + 0217c29 commit df29006
Show file tree
Hide file tree
Showing 14 changed files with 3,672 additions and 17,692 deletions.
2 changes: 1 addition & 1 deletion src/components/menu/fallback-main-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const MenuItem = ({url, title}: MenuItemType) => {
href={linkUrl}
className="flex w-full items-center p-20 text-white no-underline hover:bg-black hover:text-white hover:underline focus:bg-black focus:text-white lg:text-black-true lg:hover:bg-transparent lg:hover:text-black-true lg:focus:bg-transparent lg:focus:text-black-true lg:focus:underline"
>
<div className="pl-30 lg:pl-0">{title}</div>
<div className="shrink-0 pl-30 lg:pl-0">{title}</div>
</Link>
</li>
)
Expand Down
4 changes: 2 additions & 2 deletions src/components/menu/main-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ const MenuItem = ({
)}
aria-current={activeTrail.at(-1) === id ? "page" : undefined}
>
<div className={twMerge("pl-30 lg:pl-0", titleSpacing[menuLevel])}>{title}</div>
<div className={twMerge("shrink-0 pl-30 lg:pl-0", titleSpacing[menuLevel])}>{title}</div>
</Link>
)}

Expand All @@ -218,7 +218,7 @@ const MenuItem = ({
onClick={toggleSubmenu}
aria-expanded={submenuOpen ? "true" : "false"}
>
<span className={twMerge("pl-30 lg:pl-0", titleSpacing[menuLevel])}>{title}</span>
<span className={twMerge("shrink-0 pl-30 lg:pl-0", titleSpacing[menuLevel])}>{title}</span>
</button>
)}

Expand Down
8 changes: 5 additions & 3 deletions src/components/node/stanford-news/page-display.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const StanfordNews = async ({node, ...props}: {node: NodeStanfordNews}) => {
timeZone: "America/Los_Angeles",
})

const encodeTitle = encodeURIComponent(node.title)

return (
<article {...props} className="centered mt-50">
<StanfordNewsMetadata node={node} />
Expand All @@ -50,7 +52,7 @@ const StanfordNews = async ({node, ...props}: {node: NodeStanfordNews}) => {
<NewsSocialLink
className="text-black transition-colors hocus:text-digital-blue"
prefix="https://twitter.com/intent/tweet?url="
suffix={`&text=${node.title}`}
suffix={`&text=${encodeTitle}`}
>
<span className="sr-only">Stanford Twitter</span>
<TwitterIcon />
Expand All @@ -60,7 +62,7 @@ const StanfordNews = async ({node, ...props}: {node: NodeStanfordNews}) => {
<NewsSocialLink
className="text-black transition-colors hocus:text-digital-blue"
prefix="https://www.linkedin.com/shareArticle?mini=true&url="
suffix={`&title=${node.title}`}
suffix={`&title=${encodeTitle}`}
>
<span className="sr-only">Stanford LinkedIn</span>
<LinkedInIcon />
Expand All @@ -69,7 +71,7 @@ const StanfordNews = async ({node, ...props}: {node: NodeStanfordNews}) => {
<li className="mr-1em">
<NewsSocialLink
className="text-black transition-colors hocus:text-digital-blue"
prefix={`mailto:?subject=${node.title}&body=`}
prefix={`mailto:?subject=${encodeTitle}&body=`}
>
<span className="sr-only">Forward Email</span>
<EnvelopeIcon title="Email" width={28} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/node/stanford-publication/page-display.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const StanfordPublication = async ({node, ...props}: {node: NodeStanfordPublicat
</div>
)}

{node.suPublicationCitation?.__typename === "SuArticleJournal" &&
{node.suPublicationCitation?.__typename === "CitationSuArticleJournal" &&
node.suPublicationCitation.suJournalPublisher && (
<div className="rs-mb-2">
<h2 className="mb-01em text-16 md:text-18 2xl:text-19">Journal Name</h2>
Expand Down
4 changes: 4 additions & 0 deletions src/components/paragraph/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import SulLibguides from "@/components/paragraph/sul-libguides"
import {ParagraphUnion} from "@/lib/gql/__generated__/drupal.d"
import {ParagraphBehaviors} from "@/lib/drupal/drupal"
import EditorAlertBanner from "@/components/patterns/elements/editor-alert-banner"
import StanfordAccordionParagraph from "@/components/paragraph/stanford-accordion"

type ParagraphProps = HTMLAttributes<HTMLDivElement> & {
paragraph: ParagraphUnion
Expand Down Expand Up @@ -142,6 +143,9 @@ const ParagraphComponent = ({paragraph, singleRow = false, fullWidth = false, ..
{...props}
/>
)}
{paragraph.__typename === "ParagraphStanfordFaq" && (
<StanfordAccordionParagraph paragraph={paragraph} {...props} />
)}
</>
)
}
Expand Down
56 changes: 56 additions & 0 deletions src/components/paragraph/stanford-accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {ElementType, HtmlHTMLAttributes} from "react"
import {ParagraphStanfordFaq} from "@/lib/gql/__generated__/drupal.d"
import {twMerge} from "tailwind-merge"
import formatHtml from "@/lib/format-html"
import Accordion, {AccordionHeaderChoice} from "@/components/patterns/elements/accordion"
import ExpandCollapseAll from "@/components/patterns/elements/expand-collapse-all"
import {getParagraphBehaviors} from "."

type Props = HtmlHTMLAttributes<HTMLDivElement> & {
paragraph: ParagraphStanfordFaq
}

const StanfordAccordionParagraph = ({paragraph, ...props}: Props) => {
const behaviors = getParagraphBehaviors(paragraph)
const Heading: ElementType = behaviors.faq_accordions?.heading || "h2"

const heading = paragraph.suFaqHeadline

let accordionHeadingLevel: AccordionHeaderChoice = "h2"
if (heading) {
if (Heading === "h2") accordionHeadingLevel = "h3"
if (Heading === "h3") accordionHeadingLevel = "h4"
if (Heading === "h4") accordionHeadingLevel = "h5"
}

return (
<div {...props} className={twMerge("cc space-y-20", props.className)}>
<div className="flex flex-col items-center justify-between gap-20 md:flex-row">
{paragraph.suFaqHeadline && (
<Heading id={paragraph.id} className="text-center">
{paragraph.suFaqHeadline}
</Heading>
)}
<ExpandCollapseAll className="ml-auto" />
</div>

{paragraph.suFaqDescription && (
<div className="wysiwyg centered relative mb-20">{formatHtml(paragraph.suFaqDescription.processed)}</div>
)}

{paragraph.suFaqQuestions?.map(question => (
<Accordion
className="border-t border-black-40 last:border-b"
buttonProps={{className: "mt-15"}}
key={question.id}
button={question.suAccordionTitle}
headingLevel={accordionHeadingLevel}
>
<div className="wysiwyg centered relative">{formatHtml(question.suAccordionBody.processed)}</div>
</Accordion>
))}
</div>
)
}

export default StanfordAccordionParagraph
98 changes: 98 additions & 0 deletions src/components/patterns/elements/accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"use client"

import {HTMLAttributes, JSX, useId} from "react"
import {useBoolean} from "usehooks-ts"
import {ChevronDownIcon} from "@heroicons/react/20/solid"
import {clsx} from "clsx"
import {twMerge} from "tailwind-merge"

export type AccordionHeaderChoice = "h2" | "h3" | "h4" | "h5"

type Props = HTMLAttributes<HTMLElement> & {
/**
* Button clickable element or string.
*/
button: JSX.Element | string
/**
* Heading level element.
*/
headingLevel?: AccordionHeaderChoice
/**
* If the accordion should be visible on first render.
*/
initiallyVisible?: boolean
/**
* Button click event if the component is controlled.
*/
onClick?: () => void
/**
* Panel visibility state if the component is controlled.
*/
isVisible?: boolean
/**
* Extra attributes on the button element.
*/
buttonProps?: HTMLAttributes<HTMLButtonElement>
/**
* Extra attributes on the panel element.
*/
panelProps?: HTMLAttributes<HTMLDivElement>
}

const Accordion = ({
button,
children,
headingLevel = "h2",
onClick,
isVisible,
initiallyVisible = false,
buttonProps,
panelProps,
...props
}: Props) => {
const {value: expanded, toggle: toggleExpanded} = useBoolean(initiallyVisible)
const id = useId()

const onButtonClick = () => {
if (onClick) {
onClick()
} else {
toggleExpanded()
}
}

// When the accordion is externally controlled.
const isExpanded = onClick ? isVisible : expanded
const Heading = headingLevel ? headingLevel : "h2"

return (
<section aria-labelledby={`${id}-button`} {...props}>
<Heading id={`${id}-button`}>
<button
{...buttonProps}
className={twMerge("flex w-full items-center text-left hocus-visible:underline", buttonProps?.className)}
aria-expanded={isExpanded}
aria-controls={`${id}-panel`}
onClick={onButtonClick}
>
{button}
<ChevronDownIcon
height={30}
className={twMerge("ml-auto shrink-0 duration-150", clsx({"rotate-180": isExpanded}))}
/>
</button>
</Heading>

<div
{...panelProps}
id={`${id}-panel`}
className={twMerge(isExpanded ? "mb-20 block" : "hidden", panelProps?.className)}
role="region"
aria-labelledby={`${id}-button`}
>
{children}
</div>
</section>
)
}
export default Accordion
44 changes: 44 additions & 0 deletions src/components/patterns/elements/expand-collapse-all.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use client"

import {useBoolean} from "usehooks-ts"
import {HTMLAttributes, useEffect, useRef} from "react"
import {MinusIcon, PlusIcon} from "@heroicons/react/16/solid"
import {twMerge} from "tailwind-merge"

type Props = HTMLAttributes<HTMLButtonElement>

const ExpandCollapseAll = ({...props}: Props) => {
const {value: expand, toggle} = useBoolean(true)
const ref = useRef<HTMLButtonElement>(null)

useEffect(() => {
const buttons = ref.current?.parentElement?.parentElement?.getElementsByTagName("button") || []
for (let i = 0; i < buttons.length; i++) {
if (!expand && buttons[i].getAttribute("aria-expanded") === "false") {
buttons[i].click()
}

if (expand && buttons[i].getAttribute("aria-expanded") === "true") {
buttons[i].click()
}
}
}, [expand])

return (
<button
ref={ref}
onClick={toggle}
{...props}
className={twMerge(
"cta-button group rs-mt-neg1 flex w-fit items-center gap-5 whitespace-nowrap rounded-full border-2 border-digital-red px-26 pb-11 pt-10 text-16 font-semibold leading-display text-digital-red no-underline transition-colors hocus:bg-cardinal-red hocus:text-white hocus:underline md:text-18",
props.className
)}
>
{expand ? "Expand All" : "Collapse All"}
{expand && <PlusIcon width={20} />}
{!expand && <MinusIcon width={20} />}
</button>
)
}

export default ExpandCollapseAll
6 changes: 3 additions & 3 deletions src/components/patterns/on-this-page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react"
import Accordion from "@/components/patterns/accordion"
import SulAccordion from "@/components/patterns/sul-accordion"
import HeadingList from "@/components/patterns/headingList"

interface OnThisPageProps {
Expand All @@ -10,10 +10,10 @@ const OnThisPage = ({children}: OnThisPageProps) => {
return (
<div>
<div className="block w-full md:w-500 lg:hidden">
<Accordion button="On this page" headingLevel="h3">
<SulAccordion button="On this page" headingLevel="h3">
<HeadingList />
{children}
</Accordion>
</SulAccordion>
</div>
<div className="sticky top-0 hidden h-fit w-300 bg-fog-light px-24 pb-40 pt-16 lg:block">
<HeadingList />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type Props = HTMLAttributes<HTMLElement> & {
panelProps?: HTMLAttributes<HTMLDivElement>
}

const Accordion = ({button, children, headingLevel = "h2", ...props}: Props) => {
const SulAccordion = ({button, children, headingLevel = "h2", ...props}: Props) => {
const id = useId()
const {buttonProps, panelProps, expanded, ref} = useAccordion({buttonId: `${id}-button`})

Expand Down Expand Up @@ -77,4 +77,4 @@ const Accordion = ({button, children, headingLevel = "h2", ...props}: Props) =>
</section>
)
}
export default Accordion
export default SulAccordion
1 change: 1 addition & 0 deletions src/lib/drupal/drupal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export type ParagraphBehaviors = {
}
sul_list_styles?: {link_display_style?: Maybe<string>}
stanford_teaser?: {heading_behavior?: Maybe<"show" | "hide" | "remove">}
faq_accordions?: {heading?: "h2" | "h3" | "h4"}
}

export type StanfordNode = BasicPage | Course | Event | EventSeries | News | Person | Library | StudyPlace
Expand Down
Loading

0 comments on commit df29006

Please sign in to comment.