Skip to content

Add marketing landing page#5

Merged
Fangoling merged 11 commits intomainfrom
marketing-page
Mar 25, 2026
Merged

Add marketing landing page#5
Fangoling merged 11 commits intomainfrom
marketing-page

Conversation

@Fangoling
Copy link
Copy Markdown
Contributor

@Fangoling Fangoling commented Mar 24, 2026

Summary

  • Adds a full marketing landing page replacing the default Docusaurus home page
  • Includes hero section, student feature highlights, instructor section, feature showcase sections (run tasks, submission, AI terminal assistant), languages section, open source / Eclipse Theia section, and CTA
  • Feature showcase videos (run button, scorpio submission, terminal assistant) are deferred — loaded after page load to avoid blocking initial render
  • Eclipse Theia section uses the Theia SVG logo and links out to theia-ide.org

Components added

  • HeroSection — headline, subtext, and CTA buttons
  • StudentFeatures — key student-facing feature cards
  • InstructorSection — instructor-focused features
  • FeatureShowcase — alternating text/video sections with deferred video loading
  • LanguagesSection — supported language logos
  • OpenSourceSection — OSS cards + Eclipse Theia prominent block with upstream contributions
  • CtaSection — bottom call-to-action
  • LandingNavbar — custom navbar override for the landing page
  • SectionHeader, Button, useScrollReveal — shared utilities

Summary by CodeRabbit

  • New Features

    • Complete landing page redesign with new hero section, feature showcase areas, and call-to-action sections
    • New landing page navigation bar with logo and links
    • Scroll-reveal animations for enhanced visual engagement
    • Updated site branding and typography (DM Sans, Space Grotesk fonts)
  • Style

    • New landing page color palette and design system with responsive breakpoints
    • Enhanced mobile experience with optimized layouts

Replaces the placeholder home page with a full landing page including:
- Hero section with animated webm demo, Space Grotesk headline font, and scroll animations
- Student features, instructor, and feature showcase sections
- Languages section with SVG logos
- Open source / Eclipse Theia section
- CTA section
- Custom landing navbar, design tokens, and scroll reveal hook
- Inline codicon SVGs for all icons (no npm package)
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 24, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Refactors the landing page into modular React components (Hero, Features, Languages, Instructor, Open Source, CTA), adds landing design tokens and Google Fonts, introduces a scroll-reveal hook and LandingNavbar, and adds a Navbar wrapper that switches navbars on home routes.

Changes

Cohort / File(s) Summary
Site config & global styles
docusaurus.config.ts, src/css/custom.css
Updated site title/tagline and added Google Fonts. Added landing design tokens, dark-mode overrides, and global .reveal / .reveal.revealed rules with reduced-motion support.
Navbar wrapper & landing navbar
src/theme/Navbar/index.tsx, src/components/landing/LandingNavbar.tsx, src/components/landing/LandingNavbar.module.css
Added NavbarWrapper that renders LandingNavbar on home routes and delegates to the original theme navbar elsewhere. Implemented sticky LandingNavbar markup, logo link, Docs/GitHub links, and minimal nav styling.
Landing UI components (markup + styles)
src/components/landing/*.{tsx,module.css}, src/pages/index.tsx, src/pages/index.module.css
Added many new landing components (HeroSection, CtaSection, FeatureShowcase, StudentFeatures, InstructorSection, LanguagesSection, OpenSourceSection, SectionHeader, Button) with corresponding CSS modules; replaced previous monolithic index markup with composed sections and added section dividers. Major style relocation from index.module.css to component CSS modules.
Button component
src/components/landing/Button.tsx, src/components/landing/Button.module.css
New memoized Button component with primary/secondary variants, internal/external link handling, and CSS module styles.
Media handling & deferred load
src/components/landing/FeatureShowcase.tsx
FeatureShowcase includes media rendering (img/video) and a deferred video src strategy that waits for window load (via an internal hook), plus optional accent/reverse layout props.
Scroll reveal hook & usage
src/hooks/useScrollReveal.ts, usages in many src/components/landing/*.tsx
Added useScrollReveal (IntersectionObserver-driven one-time reveal with optional delay). Multiple landing sections attach this hook for reveal animations. Attention: timing/cleanup and reduced-motion handling.
Accessibility & ARIA
several src/components/landing/*.tsx
Sections include aria-labelledby, role="list"/listitem patterns, decorative aria-hidden wrappers, and appropriate rel on external links. Review for correct ids and semantics.

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant Router
  participant NavbarWrapper
  participant LandingNavbar
  participant ThemeNavbar
  participant LandingPage
  participant IO as IntersectionObserver

  Browser->>Router: navigate to URL
  Router->>NavbarWrapper: render navbar for current pathname
  alt pathname is home ("/" or "/Docs")
    NavbarWrapper->>LandingNavbar: render landing navbar
  else
    NavbarWrapper->>ThemeNavbar: render default theme navbar (forward props)
  end
  Browser->>LandingPage: render landing components (Hero, Features, ...)
  LandingPage->>IO: useScrollReveal attaches observer to sections
  IO->>LandingPage: onIntersect -> add `.revealed` (after optional delay)
  LandingPage->>Browser: CSS transitions run (reveal animations)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through tokens, fonts, and frames,

Buttons polished, sections play their games—
Navbar waits to choose its face,
Sections unveil with gentle pace,
A small hop for code, a bright site to embrace.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add marketing landing page' clearly and accurately summarizes the main change: introducing a complete new marketing landing page with multiple sections, components, and styling.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch marketing-page

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (7)
src/components/landing/Button.module.css (1)

1-43: Add explicit :focus-visible styles for keyboard accessibility.

Please add a visible focus state for both button variants so keyboard navigation is consistently clear.

Suggested addition
 .btnPrimary:hover {
   background: var(--landing-teal-dark);
   color: `#fff` !important;
 }
+
+.btnPrimary:focus-visible,
+.btnSecondary:focus-visible {
+  outline: 2px solid var(--landing-teal);
+  outline-offset: 2px;
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/Button.module.css` around lines 1 - 43, The
.btnPrimary and .btnSecondary styles lack an explicit keyboard-visible focus
state; add matching :focus-visible rules for both (e.g.,
.btnPrimary:focus-visible and .btnSecondary:focus-visible) that provide a clear
high-contrast outline or box-shadow while preserving border-radius and padding,
avoid removing default focus unless replaced, and ensure the focus color/outline
contrasts with the background (consistent with hover/active visuals) so keyboard
users can clearly see focus.
src/theme/Navbar/index.tsx (1)

11-13: Derive home-route detection from configured baseUrl (not hard-coded strings).

Line 12 will become fragile if baseUrl changes. Compute home matching from siteConfig.baseUrl to keep behavior consistent across deployments.

Suggested refactor
 import React from 'react';
 import { useLocation } from '@docusaurus/router';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
 import NavbarOriginal from '@theme-original/Navbar';
@@
 export default function NavbarWrapper(props: Props): React.JSX.Element {
   const { pathname } = useLocation();
-  const isHome = pathname === '/' || pathname === '/Docs/' || pathname === '/Docs';
+  const {
+    siteConfig: { baseUrl },
+  } = useDocusaurusContext();
+  const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
+  const isHome = pathname === baseUrl || pathname === normalizedBaseUrl;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/theme/Navbar/index.tsx` around lines 11 - 13, Replace the hard-coded home
checks with a comparison against the configured baseUrl from Docusaurus:
import/use useDocusaurusContext to get siteConfig.baseUrl, normalize it (ensure
it has/doesn't have a trailing slash consistently), then compute isHome by
comparing pathname to the normalized baseUrl and any expected variant (e.g.,
`${baseUrl}Docs` and `${baseUrl}Docs/`) instead of '/' and hard-coded '/Docs'
strings. Update the code that currently uses useLocation, pathname and isHome so
it references siteConfig.baseUrl (via useDocusaurusContext) and performs
normalized equality checks.
src/components/landing/HeroSection.tsx (1)

33-33: Use useBaseUrl for the demo video path.

Line 33 hard-codes '/Docs/', which couples the component to one deployment path. Resolve the asset with Docusaurus base-url helpers.

Suggested refactor
 import Button from './Button';
+import useBaseUrl from '@docusaurus/useBaseUrl';
 import styles from './HeroSection.module.css';
@@
 export default function HeroSection() {
+  const demoVideoSrc = useBaseUrl('/videos/artemis-theia-e2e.webm');
   return (
@@
-          src="/Docs/videos/artemis-theia-e2e.webm"
+          src={demoVideoSrc}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/HeroSection.tsx` at line 33, The video src is
hard-coded to '/Docs/videos/...' in the HeroSection component; import and use
Docusaurus' useBaseUrl hook in HeroSection.tsx, call const videoSrc =
useBaseUrl('/Docs/videos/artemis-theia-e2e.webm') inside the component (or
compute it where props/state live), and replace the src attribute with videoSrc
so the asset resolves against the current base URL; ensure you add the import
from '@docusaurus/useBaseUrl' and update any JSX referencing the literal path to
use the resolved videoSrc.
src/components/landing/LanguagesSection.module.css (1)

63-67: Remove redundant mobile media block (no-op duplicate).

This repeats the same grid-template-columns: repeat(2, 1fr) already applied at a wider breakpoint.

♻️ Proposed cleanup
 `@media` (max-width: 820px) {
   .inner {
     grid-template-columns: 1fr;
     gap: 2.5rem;
   }

   .langGrid {
     grid-template-columns: repeat(2, 1fr);
   }
 }
-
-@media (max-width: 480px) {
-  .langGrid {
-    grid-template-columns: repeat(2, 1fr);
-  }
-}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/LanguagesSection.module.css` around lines 63 - 67, The
media query that sets .langGrid { grid-template-columns: repeat(2, 1fr); } for
(max-width: 480px) is redundant because the same rule is already applied at a
wider breakpoint; remove this duplicate media block from
LanguagesSection.module.css so .langGrid’s layout is governed by the existing
breakpoint only, or if a different mobile layout was intended, change the inner
grid-template-columns value rather than duplicating the same rule.
src/components/landing/OpenSourceSection.module.css (1)

42-45: Differentiate teal/orange icon variants.

iconColor is passed from TSX, but both classes currently render the same color, so the variant prop has no visual impact.

🎨 Example refinement
-.iconTeal,
-.iconOrange {
-  color: var(--landing-text);
-}
+.iconTeal {
+  color: var(--landing-teal-dark);
+  background: var(--landing-teal-light);
+}
+
+.iconOrange {
+  color: var(--landing-orange-dark);
+  background: var(--landing-orange-light);
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/OpenSourceSection.module.css` around lines 42 - 45,
The .iconTeal and .iconOrange classes currently both use var(--landing-text) so
the iconColor prop has no effect; update the CSS to assign distinct color values
(e.g. var(--landing-accent-teal) for .iconTeal and var(--landing-accent-orange)
for .iconOrange or explicit hex values) and ensure the TSX uses the iconColor
prop to toggle those classes (reference the .iconTeal and .iconOrange class
names and the iconColor prop/variant in the component that renders the icon).
src/components/landing/StudentFeatures.module.css (1)

19-35: Subpixel border width may render inconsistently.

0.5px borders can render as 0px or 1px depending on the browser, display density, and zoom level. Consider using 1px for consistent rendering across devices.

Suggested fix
 .featureCard {
   flex: 1;
-  border: 0.5px solid var(--landing-border);
+  border: 1px solid var(--landing-border);
   border-radius: 14px;
   padding: 1.4rem;
   background: var(--ifm-background-color);
   transition: border-color 0.15s;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/StudentFeatures.module.css` around lines 19 - 35,
Replace the inconsistent subpixel border on .featureCard by changing the base
border from 0.5px to 1px (update the rule that currently reads "border: 0.5px
solid ...") and adjust the highlighted state (.featureCard.highlight) to a
whole-pixel thicker width (for example change the current border-width 1.5px to
2px) so hover/highlight differences remain visually distinct and render
consistently across devices.
src/pages/index.module.css (1)

8-13: Same subpixel border consideration applies here.

For consistency with the earlier suggestion, consider using 1px instead of 0.5px for the section divider border.

Suggested fix
 .sectionDivider {
   border: none;
-  border-top: 0.5px solid var(--landing-border);
+  border-top: 1px solid var(--landing-border);
   max-width: 1100px;
   margin: 0 auto;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/index.module.css` around lines 8 - 13, Update the .sectionDivider
CSS rule to use a 1px border-top instead of 0.5px to avoid subpixel rendering
inconsistencies; locate the .sectionDivider selector in
src/pages/index.module.css (the rule that currently sets border-top: 0.5px solid
var(--landing-border)) and change that value to 1px while keeping the rest of
the declaration intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docusaurus.config.ts`:
- Around line 9-11: The stylesheets entry in docusaurus.config.ts currently
loads Google Fonts; remove that external URL and instead add local font files to
your repo and declare them via `@font-face` in your custom CSS (e.g., custom.css),
then reference the local CSS from the config (replace the external URL in the
stylesheets array with the local stylesheet). Ensure the `@font-face` rules point
to the committed font files and that the font-family names match the existing
usage in your site styles.

In `@src/components/landing/HeroSection.module.css`:
- Around line 68-82: The keyframe names use camelCase and violate the Stylelint
keyframes-name-pattern; rename all keyframes to kebab-case (e.g., change
heroFadeUp -> hero-fade-up and heroFadeIn -> hero-fade-in) and update any usages
(animation, animation-name) that reference those names (search for heroFadeUp,
heroFadeIn and the other listed keyframe identifiers at lines ~96, ~114, ~130,
~138-143) so selectors and animation declarations match the new kebab-case
identifiers.

In `@src/components/landing/InstructorSection.tsx`:
- Line 58: The image src in the InstructorSection component is hardcoded to
"/Docs/img/marketing/scorpio.png"; replace this with a baseUrl-aware path by
importing and calling useBaseUrl (as used in LandingNavbar) and passing the
relative path "Docs/img/marketing/scorpio.png" (or "img/marketing/scorpio.png"
depending on your assets dir) through useBaseUrl to generate the src for the
<img> rendered by InstructorSection so the asset resolves correctly when baseUrl
changes.

In `@src/components/landing/LanguagesSection.tsx`:
- Around line 10-16: The languages array in LanguagesSection.tsx currently uses
hardcoded "/Docs/img/marketing/..." paths which break when baseUrl changes;
import useBaseUrl from "@docusaurus/useBaseUrl" in the LanguagesSection
component and call it for each logo path (e.g., replace the static logoSrc
values in the languages const with calls to useBaseUrl('/img/marketing/xxx.svg')
or compute them when the component mounts), ensuring all references to logoSrc
(used when rendering the list) use the resolved URL from useBaseUrl rather than
the "/Docs" prefix.

In `@src/components/landing/OpenSourceSection.tsx`:
- Line 53: In the OpenSourceSection component update the two misspelled
user-facing strings: change "edu ide" to the proper branding "edu IDE" and
correct "Ecplise Source" to "Eclipse Source" (or the project's intended "Open
Source" wording if that was the intent); locate the string literals inside the
OpenSourceSection.tsx component (the displayed copy around the two occurrences)
and replace them with the corrected spellings so the UI shows the proper names.

In `@src/components/landing/SectionHeader.tsx`:
- Around line 4-19: The SectionHeader component lacks a heading id, so
aria-labelledby consumers can't reference its <h2>; update SectionHeaderProps to
include a headingId: string (optional or required per your choice), accept
headingId in the SectionHeader function signature, and add that as the id
attribute on the rendered <h2> (the element rendered by SectionHeader / symbol:
SectionHeader, SectionHeaderProps); then update sections that use
aria-labelledby to pass matching values like "students-heading",
"instructors-heading", "opensource-heading".

In `@src/components/landing/StudentFeatures.module.css`:
- Around line 66-69: The CSS classes .iconTeal and .iconOrange are misleading
because they both set color: var(--landing-text); update
StudentFeatures.module.css so .iconTeal uses var(--landing-teal) and .iconOrange
uses var(--landing-orange) (or consolidate into a single .icon class and update
StudentFeatures.tsx to stop toggling by iconColor) so the styles match the
conditional in StudentFeatures.tsx that applies the classes based on the
iconColor prop.

In `@src/components/landing/StudentFeatures.tsx`:
- Around line 85-90: The useScrollReveal hook schedules setTimeout but doesn't
capture or clear the timer, causing callbacks to run after unmount; update the
hook implementation in src/hooks/useScrollReveal.ts (used by RevealCard and
other components) to store the timer ID (const timeoutId =
window.setTimeout(...)) and call clearTimeout(timeoutId) in the useEffect
cleanup (return () => { clearTimeout(timeoutId); observer.disconnect(); }) so
the reveal callback won't run on detached nodes and resources are cleaned up.

In `@src/hooks/useScrollReveal.ts`:
- Around line 21-23: In useScrollReveal, the setTimeout calls (e.g., the one
that adds 'revealed' to el when delay > 0 and the similar one around lines
33-34) create timers that aren’t cleared; store each timer id (let timer =
setTimeout(...)) and return a cleanup that calls clearTimeout(timer) and also
removes any added classes or observers as appropriate so the timeout cannot run
against a stale DOM element; update both occurrences (the delay > 0 branch and
the other delayed call) to follow this pattern and reference the same cleanup
returned by useEffect.

---

Nitpick comments:
In `@src/components/landing/Button.module.css`:
- Around line 1-43: The .btnPrimary and .btnSecondary styles lack an explicit
keyboard-visible focus state; add matching :focus-visible rules for both (e.g.,
.btnPrimary:focus-visible and .btnSecondary:focus-visible) that provide a clear
high-contrast outline or box-shadow while preserving border-radius and padding,
avoid removing default focus unless replaced, and ensure the focus color/outline
contrasts with the background (consistent with hover/active visuals) so keyboard
users can clearly see focus.

In `@src/components/landing/HeroSection.tsx`:
- Line 33: The video src is hard-coded to '/Docs/videos/...' in the HeroSection
component; import and use Docusaurus' useBaseUrl hook in HeroSection.tsx, call
const videoSrc = useBaseUrl('/Docs/videos/artemis-theia-e2e.webm') inside the
component (or compute it where props/state live), and replace the src attribute
with videoSrc so the asset resolves against the current base URL; ensure you add
the import from '@docusaurus/useBaseUrl' and update any JSX referencing the
literal path to use the resolved videoSrc.

In `@src/components/landing/LanguagesSection.module.css`:
- Around line 63-67: The media query that sets .langGrid {
grid-template-columns: repeat(2, 1fr); } for (max-width: 480px) is redundant
because the same rule is already applied at a wider breakpoint; remove this
duplicate media block from LanguagesSection.module.css so .langGrid’s layout is
governed by the existing breakpoint only, or if a different mobile layout was
intended, change the inner grid-template-columns value rather than duplicating
the same rule.

In `@src/components/landing/OpenSourceSection.module.css`:
- Around line 42-45: The .iconTeal and .iconOrange classes currently both use
var(--landing-text) so the iconColor prop has no effect; update the CSS to
assign distinct color values (e.g. var(--landing-accent-teal) for .iconTeal and
var(--landing-accent-orange) for .iconOrange or explicit hex values) and ensure
the TSX uses the iconColor prop to toggle those classes (reference the .iconTeal
and .iconOrange class names and the iconColor prop/variant in the component that
renders the icon).

In `@src/components/landing/StudentFeatures.module.css`:
- Around line 19-35: Replace the inconsistent subpixel border on .featureCard by
changing the base border from 0.5px to 1px (update the rule that currently reads
"border: 0.5px solid ...") and adjust the highlighted state
(.featureCard.highlight) to a whole-pixel thicker width (for example change the
current border-width 1.5px to 2px) so hover/highlight differences remain
visually distinct and render consistently across devices.

In `@src/pages/index.module.css`:
- Around line 8-13: Update the .sectionDivider CSS rule to use a 1px border-top
instead of 0.5px to avoid subpixel rendering inconsistencies; locate the
.sectionDivider selector in src/pages/index.module.css (the rule that currently
sets border-top: 0.5px solid var(--landing-border)) and change that value to 1px
while keeping the rest of the declaration intact.

In `@src/theme/Navbar/index.tsx`:
- Around line 11-13: Replace the hard-coded home checks with a comparison
against the configured baseUrl from Docusaurus: import/use useDocusaurusContext
to get siteConfig.baseUrl, normalize it (ensure it has/doesn't have a trailing
slash consistently), then compute isHome by comparing pathname to the normalized
baseUrl and any expected variant (e.g., `${baseUrl}Docs` and `${baseUrl}Docs/`)
instead of '/' and hard-coded '/Docs' strings. Update the code that currently
uses useLocation, pathname and isHome so it references siteConfig.baseUrl (via
useDocusaurusContext) and performs normalized equality checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ab2bcb43-29a0-4d44-a789-ce6a36cb19b5

📥 Commits

Reviewing files that changed from the base of the PR and between c06ace7 and 7cebaf7.

⛔ Files ignored due to path filters (9)
  • static/img/marketing/C_Programming_Language.svg is excluded by !**/*.svg
  • static/img/marketing/OCaml_Sticker.svg is excluded by !**/*.svg
  • static/img/marketing/java-svgrepo-com.svg is excluded by !**/*.svg
  • static/img/marketing/javascript-svgrepo-com.svg is excluded by !**/*.svg
  • static/img/marketing/page.png is excluded by !**/*.png
  • static/img/marketing/python-svgrepo-com.svg is excluded by !**/*.svg
  • static/img/marketing/rust-svgrepo-com.svg is excluded by !**/*.svg
  • static/img/marketing/scorpio.png is excluded by !**/*.png
  • static/videos/artemis-theia-e2e.webm is excluded by !**/*.webm
📒 Files selected for processing (26)
  • docusaurus.config.ts
  • src/components/landing/Button.module.css
  • src/components/landing/Button.tsx
  • src/components/landing/CtaSection.module.css
  • src/components/landing/CtaSection.tsx
  • src/components/landing/FeatureShowcase.module.css
  • src/components/landing/FeatureShowcase.tsx
  • src/components/landing/HeroSection.module.css
  • src/components/landing/HeroSection.tsx
  • src/components/landing/InstructorSection.module.css
  • src/components/landing/InstructorSection.tsx
  • src/components/landing/LandingNavbar.module.css
  • src/components/landing/LandingNavbar.tsx
  • src/components/landing/LanguagesSection.module.css
  • src/components/landing/LanguagesSection.tsx
  • src/components/landing/OpenSourceSection.module.css
  • src/components/landing/OpenSourceSection.tsx
  • src/components/landing/SectionHeader.module.css
  • src/components/landing/SectionHeader.tsx
  • src/components/landing/StudentFeatures.module.css
  • src/components/landing/StudentFeatures.tsx
  • src/css/custom.css
  • src/hooks/useScrollReveal.ts
  • src/pages/index.module.css
  • src/pages/index.tsx
  • src/theme/Navbar/index.tsx

Comment on lines +66 to +69
.iconTeal,
.iconOrange {
color: var(--landing-text);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how these icon classes are used in the StudentFeatures component
rg -n "iconTeal|iconOrange" --type tsx --type ts

Repository: EduIDE/Docs

Length of output: 82


🏁 Script executed:

# Search for uses of iconTeal and iconOrange with proper file extensions
rg -n "iconTeal|iconOrange" --type js --type jsx --type ts --type css

Repository: EduIDE/Docs

Length of output: 82


🏁 Script executed:

# Also check the StudentFeatures component directly
find . -name "*StudentFeatures*" -type f | head -20

Repository: EduIDE/Docs

Length of output: 151


🏁 Script executed:

# Look at the CSS file to understand the context better
cat -n src/components/landing/StudentFeatures.module.css | head -80

Repository: EduIDE/Docs

Length of output: 1982


🏁 Script executed:

# Check for CSS variable definitions in the project
rg "var(--landing-teal|--landing-orange|--landing-text)" --type css

Repository: EduIDE/Docs

Length of output: 37


🏁 Script executed:

# Check the StudentFeatures.tsx component to see how these classes are used
cat -n src/components/landing/StudentFeatures.tsx

Repository: EduIDE/Docs

Length of output: 4684


🏁 Script executed:

# Search for CSS variable definitions, checking the entire CSS file
rg "landing-teal|landing-orange|landing-text" --type css -A 1 -B 1

Repository: EduIDE/Docs

Length of output: 8958


Icon color classes have misleading names that don't match their styling.

In StudentFeatures.tsx (line 74), the component conditionally applies .iconTeal or .iconOrange based on the iconColor prop, but both classes apply the same color (var(--landing-text)). Their names suggest they should visually differentiate between teal and orange icons. Either apply distinct colors using the available CSS variables (var(--landing-teal) and var(--landing-orange)), or consolidate into a single class if no visual distinction is intended.

Suggested fix if distinct colors are intended
-.iconTeal,
-.iconOrange {
-  color: var(--landing-text);
-}
+.iconTeal {
+  color: var(--landing-teal);
+}
+
+.iconOrange {
+  color: var(--landing-orange);
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/StudentFeatures.module.css` around lines 66 - 69, The
CSS classes .iconTeal and .iconOrange are misleading because they both set
color: var(--landing-text); update StudentFeatures.module.css so .iconTeal uses
var(--landing-teal) and .iconOrange uses var(--landing-orange) (or consolidate
into a single .icon class and update StudentFeatures.tsx to stop toggling by
iconColor) so the styles match the conditional in StudentFeatures.tsx that
applies the classes based on the iconColor prop.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/components/landing/FeatureShowcase.tsx (1)

36-38: Defer media loading to reduce landing-page payload.

Line 36 and Line 38 currently load media eagerly. For multiple showcase blocks, this can inflate initial load cost. Add lazy/media preload hints.

♻️ Suggested diff
-          <video src={mediaSrc} autoPlay loop muted playsInline aria-label={mediaAlt} />
+          <video
+            src={mediaSrc}
+            autoPlay
+            loop
+            muted
+            playsInline
+            preload="metadata"
+            aria-label={mediaAlt}
+          />
         ) : (
-          <img src={mediaSrc} alt={mediaAlt ?? ''} />
+          <img src={mediaSrc} alt={mediaAlt ?? ''} loading="lazy" decoding="async" />
         )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/FeatureShowcase.tsx` around lines 36 - 38, The media
elements in FeatureShowcase (the <video> rendered when mediaSrc is a video and
the <img> rendered otherwise) are loading eagerly; add lazy-loading hints by
adding loading="lazy" and fetchPriority="low" to the <img> (use mediaAlt and
mediaSrc as now) and add preload="metadata" and fetchPriority="low" to the
<video>; for better deferred autoplay of videos consider wiring an
IntersectionObserver in FeatureShowcase to only call play() or render the
<video> when it's in viewport (use the existing mediaSrc, mediaAlt and the
component render path to locate where to insert these attributes/observer
logic).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/components/landing/FeatureShowcase.tsx`:
- Around line 36-38: The media elements in FeatureShowcase (the <video> rendered
when mediaSrc is a video and the <img> rendered otherwise) are loading eagerly;
add lazy-loading hints by adding loading="lazy" and fetchPriority="low" to the
<img> (use mediaAlt and mediaSrc as now) and add preload="metadata" and
fetchPriority="low" to the <video>; for better deferred autoplay of videos
consider wiring an IntersectionObserver in FeatureShowcase to only call play()
or render the <video> when it's in viewport (use the existing mediaSrc, mediaAlt
and the component render path to locate where to insert these
attributes/observer logic).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8da66353-3db7-4287-aa01-ffbd20b100d0

📥 Commits

Reviewing files that changed from the base of the PR and between 7cebaf7 and 7be1e96.

⛔ Files ignored due to path filters (3)
  • static/videos/run-button.webm is excluded by !**/*.webm
  • static/videos/scorpio.webm is excluded by !**/*.webm
  • static/videos/terminal-assistant.webm is excluded by !**/*.webm
📒 Files selected for processing (3)
  • src/components/landing/FeatureShowcase.module.css
  • src/components/landing/FeatureShowcase.tsx
  • src/pages/index.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/components/landing/FeatureShowcase.module.css
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/pages/index.tsx

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/pages/index.tsx (1)

22-51: Consider data-driving the FeatureShowcase blocks.

The three showcase sections are structurally identical; using a small config array + .map() would reduce repetition and future edit drift.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/index.tsx` around lines 22 - 51, The three repeated FeatureShowcase
blocks should be data-driven: create a small array (e.g., featureShowcases) of
objects containing the props (label, title, description, mediaSrc, mediaAlt,
mediaType, accentColor, reverse) and then render them via
featureShowcases.map(...) to return <FeatureShowcase ... /> for each item,
inserting the <hr className={styles.sectionDivider} /> between items (or render
it conditionally inside the map for all but the last index); update references
in this file to use the new array and the FeatureShowcase component name to
eliminate duplication.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pages/index.tsx`:
- Line 21: The decorative <hr> elements in the Home page should be hidden from
assistive tech: update each <hr> in src/pages/index.tsx (inside the Home
component/JSX) to include an accessibility attribute such as aria-hidden="true"
(or role="presentation"/role="none") so screen readers ignore these separators
while preserving visual styling.

---

Nitpick comments:
In `@src/pages/index.tsx`:
- Around line 22-51: The three repeated FeatureShowcase blocks should be
data-driven: create a small array (e.g., featureShowcases) of objects containing
the props (label, title, description, mediaSrc, mediaAlt, mediaType,
accentColor, reverse) and then render them via featureShowcases.map(...) to
return <FeatureShowcase ... /> for each item, inserting the <hr
className={styles.sectionDivider} /> between items (or render it conditionally
inside the map for all but the last index); update references in this file to
use the new array and the FeatureShowcase component name to eliminate
duplication.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 927f6ef0-dfcf-4e6a-ac0c-d3ee15b9f48a

📥 Commits

Reviewing files that changed from the base of the PR and between 7be1e96 and 7c441e0.

⛔ Files ignored due to path filters (1)
  • static/img/theia.svg is excluded by !**/*.svg
📒 Files selected for processing (7)
  • src/components/landing/CtaSection.module.css
  • src/components/landing/FeatureShowcase.tsx
  • src/components/landing/InstructorSection.tsx
  • src/components/landing/LanguagesSection.tsx
  • src/components/landing/OpenSourceSection.module.css
  • src/components/landing/OpenSourceSection.tsx
  • src/pages/index.tsx
✅ Files skipped from review due to trivial changes (5)
  • src/components/landing/InstructorSection.tsx
  • src/components/landing/LanguagesSection.tsx
  • src/components/landing/CtaSection.module.css
  • src/components/landing/OpenSourceSection.tsx
  • src/components/landing/OpenSourceSection.module.css
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/landing/FeatureShowcase.tsx

…m roles

- Add id prop to SectionHeader and wire it from StudentFeatures,
  InstructorSection, and OpenSourceSection so aria-labelledby resolves
- Wrap decorative ↗ arrow in aria-hidden span in OpenSourceSection
- Move role=listitem onto OssCardItem directly, removing the wrapper div
Store the timer handle so it can be cleared in the effect cleanup,
preventing a stale callback from firing on a detached element after
the component unmounts during the delay window.
…eo poster fallbacks

- HeroSection, InstructorSection, and LanguagesSection now route all
  media paths through useBaseUrl so they work regardless of the site
  base URL configuration
- Add poster attribute to video elements (hero and feature showcases)
  so an image is displayed while videos load or if they fail
- Add mediaPoster prop to FeatureShowcase to thread poster values through
- Add symmetric return to useDeferredSrc readyState branch for
  consistent cleanup behaviour
- Wrap decorative → arrow in FeatureShowcase in aria-hidden span
- Move role=listitem onto LangItem directly, removing the wrapper div
@Fangoling Fangoling merged commit 21c64f8 into main Mar 25, 2026
3 checks passed
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.

1 participant