diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b133c4e..c797996 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,7 +4,26 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +<<<<<<< HEAD importers: +======= +dependencies: + '@radix-ui/react-accordion': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1) + focus-trap-react: + specifier: ^10.2.3 + version: 10.2.3(prop-types@15.8.1)(react-dom@18.3.1)(react@18.3.1) + next: + specifier: 14.2.3 + version: 14.2.3(@babel/core@7.24.5)(react-dom@18.3.1)(react@18.3.1)(sass@1.77.1) + react: + specifier: ^18 + version: 18.3.1 + react-dom: + specifier: ^18 + version: 18.3.1(react@18.3.1) +>>>>>>> page/EdwardNew/faq-page .: dependencies: diff --git a/public/icons/plus.svg b/public/icons/plus.svg new file mode 100644 index 0000000..4bddfe0 --- /dev/null +++ b/public/icons/plus.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/app/Home.scss b/src/app/Home.scss index 27da440..07c5bf3 100644 --- a/src/app/Home.scss +++ b/src/app/Home.scss @@ -32,6 +32,7 @@ } section { + background-color: #fcfcfc; scroll-snap-align: center; padding-block: $main-padding-mobile-block; padding-inline: $main-padding-mobile-inline; diff --git a/src/app/assets/icons/chevron.svg b/src/app/assets/icons/chevron.svg new file mode 100644 index 0000000..2cd2b91 --- /dev/null +++ b/src/app/assets/icons/chevron.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/app/assets/images/Apricot.webp b/src/app/assets/images/Apricot.webp new file mode 100644 index 0000000..403f66e Binary files /dev/null and b/src/app/assets/images/Apricot.webp differ diff --git a/src/app/components/MyAccordion/MyAccordion.scss b/src/app/components/MyAccordion/MyAccordion.scss index 413bea5..5adf10c 100644 --- a/src/app/components/MyAccordion/MyAccordion.scss +++ b/src/app/components/MyAccordion/MyAccordion.scss @@ -1,125 +1,195 @@ -.AccordionRoot { - /* variables */ - $trigger-border-color: #bababa; - $trigger-padding-mobile: calc($p-size * 1.25); - $trigger-padding-desktop: calc($h3-size * 1.25); - $border-thickness: 1px; - // Used to reduce space between accordion trigger and content by ignoring trigger's padding-bottom - $content-top-offset: calc(0.75 * $trigger-padding-desktop); - - .AccordionItem { - width: 100%; - // This is to avoid double borders - border: $border-thickness solid $trigger-border-color; - border-bottom: none; - - &:last-child { - @media (min-width: $mobile-breakpoint) { - border-bottom: $border-thickness solid $trigger-border-color; - } +.accordion-container { + height: 100%; + display: flex; + flex-direction: column; + overflow-y: hidden; + overflow-x: hidden; + + .AccordionRoot { + /* variables */ + $trigger-border-color: #bababa; + $trigger-padding-mobile: calc($p-size * 1.25); + $trigger-padding-desktop: calc($h3-size * 1.25); + $border-thickness: 1px; + // Used to reduce space between accordion trigger and content by ignoring trigger's padding-bottom + $content-top-offset: calc(0.75 * $trigger-padding-desktop); + + height: 100%; + overflow-y: auto; + overflow-x: hidden; + + &::-webkit-scrollbar-track, + &::-webkit-scrollbar-track { + background: rgb(230, 230, 230); + border-radius: 1rem; } - } - .AccordionColumn { - // Avoid double border on right side when there are 2 columns - &:not(:first-child) { - @media (min-width: $mobile-breakpoint) { - transform: translateX(-$border-thickness); - } + &::-webkit-scrollbar { + width: 8px; } - // Add border bottom for mobile - &:last-child { - .AccordionItem:last-child { - border-bottom: $border-thickness solid $trigger-border-color; - } + &::-webkit-scrollbar-thumb { + background: rgb(182, 182, 182); + border-radius: 1rem; } - } - .AccordionTrigger { - border: none; - font-family: $subheading-font; - font-size: $p-size; - padding: $trigger-padding-mobile; - color: $primary-black; - background-color: transparent; - display: flex; - align-items: center; - justify-content: space-between; - gap: 5px; - width: 100%; - text-align: left; - text-transform: uppercase; - - @media (min-width: $tablet-breakpoint) { - & { - font-size: $h3-size; - padding: $trigger-padding-desktop; - } + &::-webkit-scrollbar-thumb:hover { + background: rgb(163, 163, 163); } - } - .AccordionContent { - overflow: hidden; + .AccordionItem { + width: 100%; + background-color: $primary-white; + // This is to avoid double borders + border: $border-thickness solid $trigger-border-color; + border-bottom: none; - &[data-state='open'] { - animation: slideDown 300ms forwards; + &:last-child { + @media (min-width: $desktop-breakpoint) { + border-bottom: $border-thickness solid $trigger-border-color; + } + } } - &[data-state='closed'] { - animation: slideUp 300ms; + + .AccordionColumn { + // Avoid double border on right side when there are 2 columns + &:not(:first-child) { + @media (min-width: $desktop-breakpoint) { + transform: translateX(-$border-thickness); + } + } + + // Add border bottom for mobile + &:last-child { + .AccordionItem:last-child { + border-bottom: $border-thickness solid $trigger-border-color; + } + } } - p { + .AccordionTrigger { + border: none; + font-family: $subheading-font; + font-size: $p-size; padding: $trigger-padding-mobile; - padding-top: 0; + color: $primary-black; + background-color: $primary-white; + display: flex; + align-items: center; + justify-content: space-between; + gap: 5px; + width: 100%; + text-align: left; + text-transform: uppercase; @media (min-width: $tablet-breakpoint) { - padding: $trigger-padding-desktop; - padding-top: 0; + & { + font-size: $h3-size; + padding: $trigger-padding-desktop; + } } } - } - .AccordionIcon { - transition: transform 300ms; - width: 20px; - height: 20px; - flex-shrink: 0; + .AccordionContent { + overflow: hidden; + + &[data-state='open'] { + animation: slideDown 300ms forwards; + } + &[data-state='closed'] { + animation: slideUp 300ms; + } + + p { + padding: $trigger-padding-mobile; + padding-top: 0; - @media (min-width: $tablet-breakpoint) { - width: 28px; - height: 28px; + @media (min-width: $tablet-breakpoint) { + padding: $trigger-padding-desktop; + padding-top: 0; + } + } } - } - .AccordionTrigger[data-state='open'] > .AccordionIcon { - transform: rotate(225deg); - } - @keyframes slideDown { - from { - height: 0; + .AccordionIcon { + transition: transform 300ms; + width: 20px; + height: 20px; + flex-shrink: 0; + + @media (min-width: $tablet-breakpoint) { + width: 28px; + height: 28px; + } } - to { - height: calc(var(--radix-accordion-content-height) - $content-top-offset); - transform: translateY(calc(-1 * $content-top-offset)); + .AccordionTrigger[data-state='open'] > .AccordionIcon { + transform: rotate(225deg); + } + + @keyframes slideDown { + from { + height: 0; + } + to { + height: calc( + var(--radix-accordion-content-height) - $content-top-offset + ); + transform: translateY(calc(-1 * $content-top-offset)); + } } - } - @keyframes slideUp { - from { - height: calc(var(--radix-accordion-content-height) - $content-top-offset); - transform: translateY(calc(-1 * $content-top-offset)); + @keyframes slideUp { + from { + height: calc( + var(--radix-accordion-content-height) - $content-top-offset + ); + transform: translateY(calc(-1 * $content-top-offset)); + } + to { + height: 0; + } } - to { - height: 0; + + @media (min-width: $desktop-breakpoint) { + & { + display: grid; + grid-template-columns: repeat(2, 1fr); + } } } - // breakpoint should be a little bigger since text still wraps a little at this size - @media (min-width: $mobile-breakpoint) { - & { - display: grid; - grid-template-columns: repeat(2, 1fr); + .expand-all-btn-container { + display: none; + @media (min-width: $desktop-breakpoint) { + & { + display: flex; + justify-content: flex-end; + } + } + + .expand-all-btn { + font-family: $subheading-font; + font-size: $p-size; + + background-color: transparent; + border: none; + + display: flex; + align-items: center; + gap: 5px; + padding: 0; + margin-block-end: $p-size; + + .cheveron { + transition: transform 300ms; + width: 24px; + height: 24px; + flex-shrink: 0; + } + + &.expanded > .cheveron { + transform: rotate(90deg); + } } } } diff --git a/src/app/components/MyAccordion/MyAccordion.tsx b/src/app/components/MyAccordion/MyAccordion.tsx index 828cb61..87362e8 100644 --- a/src/app/components/MyAccordion/MyAccordion.tsx +++ b/src/app/components/MyAccordion/MyAccordion.tsx @@ -3,7 +3,8 @@ import './MyAccordion.scss'; import * as Accordion from '@radix-ui/react-accordion'; import PlusIcon from '@/assets/icons/plus-icon.svg'; -import { useRef } from 'react'; +import CheveronIcon from '@/assets/icons/chevron.svg'; +import { useRef, useState } from 'react'; import { useSetAdjacentTriggerHeight } from './hooks/useSetAdjacentTriggerHeight'; export type AccordionDataItem = { @@ -20,50 +21,135 @@ const COLUMN_COUNT = 2; export default function MyAccordion({ accordionData }: AccordionTabProps) { const triggerRefs = useRef<(HTMLButtonElement | null)[]>([]); - // Ensures that the height of adjacent accordion triggers are the same useSetAdjacentTriggerHeight({ triggerRefs, accordionData, COLUMN_COUNT }); + const [isExpandAll, setIsExpandAll] = useState(false); + const [expandedItems, setExpandedItems] = useState([]); + + const handleExpandAll = () => { + if (isExpandAll) { + setExpandedItems([]); // Collapse all items + setIsExpandAll(false); + } else { + setExpandedItems(accordionData.map(item => `accordion-${item.id}`)); // Expand all items + setIsExpandAll(true); + } + }; + + const handleValueChange = (newValues: string[]) => { + if (isExpandAll && newValues.length === 0) { + setExpandedItems([]); + setIsExpandAll(false); + } else { + setExpandedItems(newValues); + } + }; + return ( - - {[...Array(COLUMN_COUNT)].map((_column, columnIndex) => ( -
+ + + + + {isExpandAll ? ( + + {[...Array(COLUMN_COUNT)].map((_column, columnIndex) => ( +
+ {accordionData + .slice( + (columnIndex * accordionData.length) / COLUMN_COUNT, + (columnIndex * accordionData.length) / COLUMN_COUNT + + accordionData.length / COLUMN_COUNT + ) + .map((item, rowIndex) => ( + + + { + triggerRefs.current[ + (columnIndex * accordionData.length) / 2 + rowIndex + ] = element; + }} + > + {item.header} + + + + +

{item.content}

+
+
+ ))} +
+ ))} +
+ ) : ( + - {accordionData - .slice( - (columnIndex * accordionData.length) / COLUMN_COUNT, - (columnIndex * accordionData.length) / COLUMN_COUNT + - accordionData.length / COLUMN_COUNT - ) - .map((item, rowIndex) => ( - - - { - triggerRefs.current[ - (columnIndex * accordionData.length) / 2 + rowIndex - ] = element; - }} + {[...Array(COLUMN_COUNT)].map((_column, columnIndex) => ( +
+ {accordionData + .slice( + (columnIndex * accordionData.length) / COLUMN_COUNT, + (columnIndex * accordionData.length) / COLUMN_COUNT + + accordionData.length / COLUMN_COUNT + ) + .map((item, rowIndex) => ( + - {item.header} - - - - -

{item.content}

-
-
- ))} -
- ))} -
+ + { + triggerRefs.current[ + (columnIndex * accordionData.length) / 2 + rowIndex + ] = element; + }} + > + {item.header} + + + + +

{item.content}

+
+ + ))} +
+ ))} +
+ )} + ); } diff --git a/src/app/components/Navbar/Navbar.tsx b/src/app/components/Navbar/Navbar.tsx index d7f231d..03b04be 100644 --- a/src/app/components/Navbar/Navbar.tsx +++ b/src/app/components/Navbar/Navbar.tsx @@ -81,7 +81,6 @@ export default function Navbar({ pageRefs }: NavbarProps) { { isHamburgerOpen ? toggleHamburger() : null; - setCurrPage(PAGE_TYPES[index]); }} >
diff --git a/src/app/pages/FAQ/FAQ.scss b/src/app/pages/FAQ/FAQ.scss index d49ff2c..72d39d5 100644 --- a/src/app/pages/FAQ/FAQ.scss +++ b/src/app/pages/FAQ/FAQ.scss @@ -1,11 +1,79 @@ #faq { + $mobile-apricot-lower-breakpoint: 720px; + display: flex; + flex-direction: column; + position: relative; + h2 { margin-bottom: $main-padding-mobile-block; } + #apricot-container, + .apricot.mobile { + display: none; + z-index: -1; + } + @media (min-width: $mobile-breakpoint) { + overflow: hidden; + h2 { + margin-bottom: calc($main-padding-mobile-block); + } + } + + @media ($mobile-apricot-lower-breakpoint < width < $tablet-breakpoint) { + .apricot.mobile { + display: block; + position: absolute; + width: 30%; + height: auto; + } + + #apricot-1 { + top: 20%; + left: -20%; + transform: rotate(20deg); + } + + #apricot-2 { + bottom: 20%; + right: -15%; + transform: rotate(-30deg); + } + } + + @media (min-width: $desktop-breakpoint) { h2 { - margin-bottom: $main-padding-desktop-block; + margin-bottom: calc($main-padding-mobile-block - 24px); + } + + #apricot-container { + display: flex; + position: absolute; + align-items: baseline; + justify-content: center; + gap: 10%; + bottom: -5%; + width: calc(100% - 2 * $main-padding-desktop-inline); + + .apricot { + transform: rotate(-10deg); + + &#apricot-3 { + height: 15%; + width: 15%; + } + + &#apricot-4 { + height: 20%; + width: 20%; + } + + &#apricot-5 { + height: 25%; + width: 25%; + } + } } } } diff --git a/src/app/pages/FAQ/FAQ.tsx b/src/app/pages/FAQ/FAQ.tsx index 5d5c5a9..e5521a3 100644 --- a/src/app/pages/FAQ/FAQ.tsx +++ b/src/app/pages/FAQ/FAQ.tsx @@ -1,7 +1,9 @@ import './FAQ.scss'; -import { PageRef } from '@/page'; import MyAccordion from '@/components/MyAccordion/MyAccordion'; import { FAQContent } from './constants'; +import Image from 'next/image'; +import Apricot from '@/assets/images/Apricot.webp'; +import { PageRef } from '@/page'; type FAQProps = { faqRef: PageRef; @@ -13,6 +15,25 @@ export default function FAQ({ faqRef }: FAQProps) {

.04 / FAQ

Frequently Asked Questions

+ + apricot + apricot + +
+ apricot + apricot + apricot +
); } diff --git a/src/app/pages/FAQ/constants.ts b/src/app/pages/FAQ/constants.ts index 6be59d8..be30798 100644 --- a/src/app/pages/FAQ/constants.ts +++ b/src/app/pages/FAQ/constants.ts @@ -1,9 +1,9 @@ export const FAQContent = [ { id: 'item-1', - header: 'Who is eligible?', + header: 'Who is eligible to participate in UP-Grade?', content: - 'Eligibility is offered to all UCSD students and recent graduates — of various backgrounds, experience levels, and majors! We encourage anyone interested to apply, to learn and offer their one-of-a-kind knowledge!' + 'Eligibility is offered to all UCSD students and recent graduates — of various backgrounds, experience levels, and majors! We encourage anyone interested to apply, to learn, and offer their unique knowledge.' }, { id: 'item-2', @@ -14,7 +14,7 @@ export const FAQContent = [ id: 'item-3', header: 'How many people will be accepted?', content: - 'UP-Grade will have 6 student teams, with 6 participants in each team — 36 participants total. For each topic, there will be 2 teams assigned.' + 'UP-Grade will have 7 student teams, with 6 participants in each team — 42 participants total.' }, { id: 'item-4', diff --git a/src/app/styles/variables.scss b/src/app/styles/variables.scss index 3d39ffb..8c64ded 100644 --- a/src/app/styles/variables.scss +++ b/src/app/styles/variables.scss @@ -11,7 +11,8 @@ $subheading-font: var(--font-uncutsans-medium); // Breakpoints $mobile-breakpoint: 550px; -$tablet-breakpoint: 1000px; +$tablet-breakpoint: 979px; +$desktop-breakpoint: 1440px; // Sizes $nav-width: clamp(250px, 200px + 11vw, 470px);