Skip to content

Feature/home carousel#83

Open
GladwynChua wants to merge 5 commits into
mainfrom
feature/home-carousel
Open

Feature/home carousel#83
GladwynChua wants to merge 5 commits into
mainfrom
feature/home-carousel

Conversation

@GladwynChua
Copy link
Copy Markdown
Contributor

What does this PR do?

Created a carousel for mock images tentatively will replace once images are confirmed. Event titles at the top are just mock names. Responsive with mobile version by swiping. HREF for linking between albums needs to be confirmed as well.

Type of change

  • Feature
  • Bug fix
  • Chore / config
  • Hotfix

Checklist

  • My branch follows the naming convention (feature/, fix/, chore/, hotfix/)
  • My commit messages follow the conventional commits format
  • CI checks pass

Linked Issues

Closes #71

@GladwynChua
Copy link
Copy Markdown
Contributor Author

Currently HREF not confirmed for the albums. Unsure which images should be displayed on the carousel, so mock images are used.

Copy link
Copy Markdown
Collaborator

@oorjagandhi oorjagandhi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! I noticed there are some differences between this and the Figma file, more specifically

  • the 'View Album' button styling
  • the styling of the text on the top right
  • the left / right buttons
  • the nav buttons on the carousel should be centred.

You should also create a 'gallery' component and just use that in the app page for improved modularity. Overall good work tho! :)

Copy link
Copy Markdown
Collaborator

@joengy joengy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! Carousel behaves well and CI's green. Main ask is to pull it into its own Gallery component left a few small notes inline. Happy to re-review once that's done but overall good job.

Comment thread web/src/app/page.tsx
},
]

export default function Home() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you extract this into its own component, e.g. web/src/components/Gallery.tsx(or Carousel.tsx)? Right now page.tsx is mostly carousel logic, which breaks the per-component pattern used by Hero, HighlightCard, InstagramFeed etc., and forces the entire home page to be 'use client'.

Comment thread web/src/app/page.tsx Outdated
Comment on lines +64 to +68
},
[startTimer],
)

const goPrev = useCallback(() => {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

goPrev and goNext both read current directly, so they have to list it in their dependency arrays. That means every time the slide advances (every 6s, plus on every user interaction), React throws away the old callbacks and creates fresh ones, which also recreates handleTouchEnd (since it depends on them). It's not a visible bug, just unnecessary churn.

You can avoid it by reading the previous value from setCurrent's updater function instead of from the closure, then the callbacks don't need current at all and stay stable across renders:

const goPrev = useCallback(() => { setCurrent((c) => (c - 1 + carouselImages.length) % carouselImages.length) startTimer() }, [startTimer])

const goNext = useCallback(() => { setCurrent((c) => (c + 1) % carouselImages.length) startTimer() }, [startTimer])

Comment thread web/src/app/page.tsx Outdated
<section>
<div className="relative">
<div
className="relative w-full aspect-[16/7] sm:aspect-[16/7] overflow-hidden"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sm:aspect-[16/7] is the same value as the base so can drop the sm: variant.

Comment thread web/src/app/page.tsx
/>
</section>

{/* Image Carousel */}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The carousel pauses on hover but not on keyboard focus so a keyboard user tabbing to the prev/next buttons will have slides advancing under them. Could you add onFocus={stopTimer} / onBlur={startTimer} (or equivalent focus-within logic) so it pauses for keyboard users too?

Copy link
Copy Markdown
Collaborator

@joengy joengy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The home carousel is looking good, however theres some small changes that need to be done so I left some comments for those. Othewise good job overall Gladwyn.

Comment thread web/src/app/page.tsx
@@ -1,8 +1,10 @@
'use client'
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop this 'use client'. HomeCarousel already declares its own 'use client' boundary, so importing it from a server component works fine. Marking the homepage as a client component opts the whole route (Hero, HighlightCard, InstagramFeed, Footer) out of server rendering for no benefit.

Comment on lines +130 to +132
<a
href={image.albumHref}
className="inline-flex items-center gap-2 border-2 rounded-xl border-ssa-white bg-transparent text-ssa-white font-averia font-semibold text-sm md:text-base px-5 py-2 transition-colors cursor-pointer hover:bg-white/20"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Albums are internal routes per PR #87 (/events/[eventID]), so use next/link instead of a raw <a> to get client-side navigation and prefetching:

import Link from 'next/link'
// ...
<Link
  href={image.albumHref}  // e.g. `/events/${eventId}`
  className="inline-flex items-center gap-2 border-2 rounded-xl border-ssa-white bg-transparent text-ssa-white font-averia font-semibold text-sm md:text-base px-5 py-2 transition-colors cursor-pointer hover:bg-white/20"
>
  View Album →
</Link>

Comment thread web/package-lock.json
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like the result of a stray npm install so could you please revert all changes to web/package-lock.json (e.g. git checkout origin/main -- web/package-lock.json) and run pnpm install instead. The added rows are just @next/swc-* optional platform packages that pnpm/Next resolve automatically, so pnpm-lock.yaml likely doesn't need to move either.

No need to delete the file itself as I'm putting up a separate chore PR to remove web/package-lock.json from tracking. Once that lands you can rebase and the lockfile will be gone entirely.

Comment on lines +142 to +156
<div className="absolute bottom-4 left-0 right-0 flex justify-center gap-2">
{carouselImages.map((_, index) => (
<button
key={index}
onClick={() => goTo(index)}
aria-label={`Go to slide ${index + 1}`}
className="flex items-center justify-center w-6 h-6 cursor-pointer"
>
<span
className={`block w-2.5 h-2.5 rounded-full transition-all duration-200 ${index === current ? 'bg-ssa-red scale-125' : 'bg-white/70'}`}
/>
</button>
))}
</div>
</div>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dots row is at bottom-4 and so is the "View Album" button so they'll visually overlap on narrow viewports, and the dots may also intercept clicks intended for the button. I attached an image of what that would look like on the mobile view.

Image

Comment on lines +113 to +114
{carouselImages.map((image, index) => (
<div key={index} className="relative h-full w-full shrink-0">
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key={index} is fine while the list is static, but once slides come from CMS data prefer a stable id (e.g. eventId or slug) so React doesn't reconcile the wrong slide if order changes.

Comment on lines +46 to +48
intervalRef.current = setInterval(() => {
setCurrent((prev) => (prev + 1) % carouselImages.length)
}, 6000)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The auto-advance should respect prefers-reduced-motion and give users a way to pause. Minimum change is gating the interval on the OS setting:

useEffect(() => {
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return
  startTimer()
  return () => { if (intervalRef.current) clearInterval(intervalRef.current) }
}, [startTimer])

Copy link
Copy Markdown
Collaborator

@oorjagandhi oorjagandhi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating the width of the gallery! Just some changes:

  • the font for title top left should be thinner to match Figma
  • also the top left title should have more spacing from top left corner
  • arrows should be less opaque
  • view album button should have more spacing from the bottom right corner
  • view album button should be bigger
  • add a drop shadow on component

Overall good job! Most of the changes are to better match the Figma. In the future it'd be great if you did a side-by-side check with Figma before putting up a PR, so you can catch differences early and minimize the amount of changes you need to make during review :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HOME-04 - Gallery carousel

3 participants