Skip to content

feat(redesign): Homepage Hero component#2203

Open
g-francesca wants to merge 21 commits intoredesignfrom
redesign-homepage
Open

feat(redesign): Homepage Hero component#2203
g-francesca wants to merge 21 commits intoredesignfrom
redesign-homepage

Conversation

@g-francesca
Copy link
Collaborator

@g-francesca g-francesca commented Mar 2, 2026

Preview
This PR implements the homepage Hero component.

What's included

  • Background video (light/dark mode variants) with poster images for mobile fallback
  • Code blocks using Expressive Code. It was installed primarily to get a built-in copy button on the Hero code blocks, something Shiki doesn't provide out of the box.
  • Fully responsive layout

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or

(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or

(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.

(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.

@g-francesca g-francesca requested a review from a team as a code owner March 2, 2026 11:57
@netlify
Copy link

netlify bot commented Mar 2, 2026

Deploy Preview for expressjscom-preview ready!

Name Link
🔨 Latest commit 34fdcd9
🔍 Latest deploy log https://app.netlify.com/projects/expressjscom-preview/deploys/69a70090c2a4bf00084e1f34
😎 Deploy Preview https://deploy-preview-2203--expressjscom-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 100 (🟢 up 4 from production)
Accessibility: 100 (🟢 up 13 from production)
Best Practices: 100 (no change from production)
SEO: 100 (🟢 up 6 from production)
PWA: 80 (🟢 up 50 from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@socket-security
Copy link

socket-security bot commented Mar 2, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​typescript-eslint@​8.53.11001007498100
Addednpm/​astro-expressive-code@​0.41.71001007491100
Addednpm/​typescript@​5.9.31001009010090

View full report

const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang);

const EXPRESS_VERSION = '5.2.1';
Copy link
Member

Choose a reason for hiding this comment

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

Currently we have an automation on the site to update the version. I’m not sure how to suggest it here, since it could be done with a fetch on each build or we could continue with the automation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right, I can fetch the latest version from the npm registry, so we're sure it's updated on every build. I can add a fallback (that can be just for example 5.x) just in case the npm registry is not reachable. wdyt?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, I think that sounds good. I think it would be fine to use https://npm.antfu.dev/express to simplify things.

Copy link
Member

Choose a reason for hiding this comment

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

Now that I think about it, we don’t need that many automations anymore. Astro can handle them for us, which is pretty cool. I’m just saying this for pulling in the READMEs from our middlewares.
https://github.com/withastro/docs/blob/8e216293f74f38cc64db427622de74060403d5a8/src/content.config.ts#L168

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Nice! I didn't know that. I've reviewed the content config to use the content collection loader

Copy link
Contributor

@krzysdz krzysdz left a comment

Choose a reason for hiding this comment

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

I was wondering what is the pause/play button supposed to do, because in my browser the (light) video did not play so it did nothing. The light video is encoded with 4:4:4 chroma subsampling, which is not supported by my browser's decoder. AVC/H264 4:4:4 is not even listed in AMD, Intel or Nvidia video decode support matrix.

Error Code: NS_ERROR_DOM_MEDIA_FATAL_ERR (0x806e0005)
Details: auto __cdecl mozilla::SupportChecker::AddMediaFormatChecker(const TrackInfo &)::(anonymous class)::operator()(void) const: Decoder may not have the capability to handle the requested video format with YUV444 chroma subsampling.

The video files are small, which is nice, but look very much compressed and so does the light static fallback image.

If someone blocks autoplay, then the initial button state is wrong - pause button must be clicked to play the video (later the state is synchronised).

The button, when hovered, is partially clipped by the code block in mobile view (open page with enough width to load in desktop mode and then make it smaller to force mobile mode).
pause button clipped on top

@g-francesca
Copy link
Collaborator Author

I was wondering what is the pause/play button supposed to do, because in my browser the (light) video did not play so it did nothing. The light video is encoded with 4:4:4 chroma subsampling, which is not supported by my browser's decoder. AVC/H264 4:4:4 is not even listed in AMD, Intel or Nvidia video decode support matrix.

Error Code: NS_ERROR_DOM_MEDIA_FATAL_ERR (0x806e0005)
Details: auto __cdecl mozilla::SupportChecker::AddMediaFormatChecker(const TrackInfo &)::(anonymous class)::operator()(void) const: Decoder may not have the capability to handle the requested video format with YUV444 chroma subsampling.

@krzysdz Can you please check now and tell me if the video plays now? The pause/play button is supposed to play or pause the video on demand, I've also reviewed the style so that, in case the video fails loading for any reasons, the button is not displayed.

The video files are small, which is nice, but look very much compressed and so does the light static fallback image.

Ok, so in this case I can try to review video/images to find a better compromise between quality and size.

If someone blocks autoplay, then the initial button state is wrong - pause button must be clicked to play the video (later the state is synchronised).

Right, thanks for reporting it. It's fixed now

The button, when hovered, is partially clipped by the code block in mobile view (open page with enough width to load in desktop mode and then make it smaller to force mobile mode). pause button clipped on top

As the video are not loaded on mobile for performance reasons, I've actually hidden the button on mobile.

Copy link
Member

Choose a reason for hiding this comment

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

For the others, there are still some things to add, as well as the banner

@g-francesca
Copy link
Collaborator Author

The video files are small, which is nice, but look very much compressed and so does the light static fallback image.

@krzysdz I've reviewed video/poster images to find a better compromise between size and quality. Let me know how they look to you now. TY

}
});
},
{ rootMargin: '5rem' }
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
{ rootMargin: '5rem' }
{ rootMargin: '80px' }

I didn't review all the code, but this caught my attention. rem is not supported by rootMargin. Please fix it. Also, you can verify it in your console.

Actually it is spec bug w3c/IntersectionObserver#308

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

right, it's fixed now. thanks for catching it

}
});
},
{ rootMargin: '5rem' }
Copy link
Contributor

Choose a reason for hiding this comment

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

Uncaught DOMException: IntersectionObserver constructor: rootMargin must be specified in pixels or percent.

The specification says that it has to be "a string of 1-4 components, each either an absolute length or a percentage".

Because of this exception more things are broken for me (e.g. the resize listener)

@ShubhamOulkar
Copy link
Member

ShubhamOulkar commented Mar 3, 2026

Also Light theme looks weird.

image

EDIT :- It is because of my browser 3g throttle. We might have performance issue. Let's test it in separate PR. Now theme looks OK to me.

image

@krzysdz
Copy link
Contributor

krzysdz commented Mar 3, 2026

I can confirm that now both videos can be played by my browser.

The exception thrown by the IntersectionObserver aborts the script execution, so some more things are broken - e.g. I can start the video as "desktop", resize to mobile (video keeps playing, but play/pause button is gone) and then changing the theme doesn't work on the video allowing for light video in dark mode or video with black background in light mode (with black text on black background).

@socket-security
Copy link

socket-security bot commented Mar 3, 2026

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm vite is 91.0% likely obfuscated

Confidence: 0.91

Location: Package overview

From: astro/package-lock.jsonnpm/astro@5.18.0npm/vite@6.4.1

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/vite@6.4.1. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@g-francesca
Copy link
Collaborator Author

g-francesca commented Mar 3, 2026

Also Light theme looks weird.

image EDIT :- It is because of my browser 3g throttle. We might have performance issue. Let's test it in separate PR. Now theme looks OK to me. image

mmm yes, I could reproduce that with slow connection. I've noted this for later fix. Thanks

I spotted the issue @ShubhamOulkar, should be solved now.


// https://astro.build/config
export default defineConfig({
site: 'https://expressjs.com',
Copy link
Member

Choose a reason for hiding this comment

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

We still need the site.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I removed it by mistake. Thanks for the catch. Fixed now.

<ul>
<li>
{t('home.reviewDesignSystemPrefix')}
<a href={`/${lang}/ds-foundations`}>{t('home.reviewDesignSystemLink')}</a>
Copy link
Member

Choose a reason for hiding this comment

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

I really like having that page, could we add it to the menu under the Resources section?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I added the ds-foundations page for internal reference, but of course if you find this useful, we can add it. I leave the decision to you, let me know in case :)

@g-francesca
Copy link
Collaborator Author

I can confirm that now both videos can be played by my browser.

The exception thrown by the IntersectionObserver aborts the script execution, so some more things are broken - e.g. I can start the video as "desktop", resize to mobile (video keeps playing, but play/pause button is gone) and then changing the theme doesn't work on the video allowing for light video in dark mode or video with black background in light mode (with black text on black background).

@krzysdz I fixed the IntersectionObserver, so you should not reproduce the other related bugs. About the theme switcher not updating the video accordingly, is it a problem you can reproduce in specific cases? Or it's always like this?

Copy link
Member

Choose a reason for hiding this comment

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

And when the user has animations disabled, does this respect that as well?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@bjohansebas do you mean blocking the autoplay when animation is disabled?

Copy link
Member

Choose a reason for hiding this comment

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

yep!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, it's blocked if user preference is set to reduced motion

@krzysdz
Copy link
Contributor

krzysdz commented Mar 3, 2026

About the theme switcher not updating the video accordingly, is it a problem you can reproduce in specific cases? Or it's always like this?

It works now after the IntersectionObserver fix.

return;
}

const isMobile = window.innerWidth < breakpointMd;
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Do you refer to the logic to disable video on mobile right? I moved it in a function that is called on load and on resize.

const targetSrc = getVideoSource();

if (currentSrc && targetSrc && !currentSrc.endsWith(targetSrc)) {
const source = video.querySelector('source');
Copy link
Member

Choose a reason for hiding this comment

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

const alternateVideoSrc = getCurrentTheme() === 'dark' ? videoDesktopLight : videoDesktop;
if (alternateVideoSrc) {
const link = document.createElement('link');
link.rel = 'preload';
Copy link
Member

Choose a reason for hiding this comment

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

Why not to use two simple prefetch links in the html?

<link rel="prefetch" href="/hero-background-light.mp4" as="video">
<link rel="prefetch" href="/hero-background.mp4" as="video">

Instead of dynamically adding a preload link for the alternate theme video, we might consider using static prefetch links (possibly desktop-only) for both theme variants and simply switch the src on theme change. Since this is decorative background media, prefetch would be lower priority and less aggressive than preload, reducing bandwidth pressure while still keeping theme switching smooth.

Copy link
Member

Choose a reason for hiding this comment

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

You removed preload in 89531de

@ShubhamOulkar
Copy link
Member

😅 It’s 8:41 PM, I’m hungry, and I’m just clicking anywhere at this point. That’s it for today. 👋 Bye!

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.

4 participants