Conversation
* feat: add new appshell, navbar, projects, recentblogs sections * feat: add recent-blogs, resources, subscription sections * feat: add main heading, and Labrada font to tailwind
…from figma (needs further review), Added animations for site-load.
…o project sections
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughAdds a new AppShell, navbar, footer scaffold, announcement and content sections, scroll-reveal hooks and CSS animations, several new atom/molecule components, updates many MDX pages to forward props into ContentPageShell, and small build/config edits (.gitignore, package.json, tailwind). Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant Browser as Browser
participant App as AppShellNew
participant Nav as NavBarNew
participant Hook as useScrollReveal
participant Router as Gatsby/Router
User->>Browser: navigate / load page
Browser->>App: mount AppShellNew (renders Helmet, NavBarNew, children)
App->>Nav: render NavBarNew (attach scroll listener)
Browser->>Hook: observe sections (Announcements, Projects, RecentBlogs)
Note over Hook,Browser: IntersectionObserver adds "visible" class when in view
User->>Browser: scroll
Browser->>Nav: scroll event → NavBarNew updates backgroundPositionX (parallax)
User->>App: click DashedButton
App->>Router: navigate(to internal or external URL)
Router-->>Browser: route change / external navigation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 14
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (9)
uli-website/src/components/atoms/DashedButton.jsx-5-8 (1)
5-8:⚠️ Potential issue | 🟡 MinorSet an explicit button type to avoid accidental form submission.
Without
type="button", this defaults tosubmitinside forms and can trigger unintended submits.Suggested fix
<button + type="button" className={`font-labrada bg-transparent cursor-pointer border-[0.5px] border-solid [border-image-source:url('/dashed-btn-bg.png')] [border-image-slice:0%_fill] [border-image-repeat:round] hover:bg-[`#FFC8A6`] active:bg-[`#F28948`] ${className}`} onClick={onClick} >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/atoms/DashedButton.jsx` around lines 5 - 8, In the DashedButton.jsx component the rendered <button> currently has no explicit type, which causes it to act as a submit inside forms; update the button element in the DashedButton component to include an explicit type (e.g., type="button") or accept a type prop with a default of "button" so callers can override it; ensure you update the JSX where className and onClick are used and preserve existing props and behavior.uli-website/src/pages/new-home.js-40-40 (1)
40-40:⚠️ Potential issue | 🟡 MinorPlaceholder link
to="#"for "Our Process".The "Our Process" link navigates to
#, which doesn't lead anywhere meaningful. Consider either linking to the actual destination, or adding aTODOcomment if the page isn't ready yet to track this for follow-up.Would you like me to open an issue to track adding the actual "Our Process" page link?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/pages/new-home.js` at line 40, The NavLinkNew instance for "Our Process" uses a placeholder prop to="#" which doesn't navigate to a real route; update the NavLinkNew element's to prop to the correct route (e.g., "/our-process" or the actual destination used elsewhere) or, if the page isn't ready yet, replace the placeholder with a clear TODO comment and/or link to a pending issue ID to track it (reference the NavLinkNew component and its to prop).uli-website/src/components/molecules/FooterNew.jsx-16-20 (1)
16-20:⚠️ Potential issue | 🟡 MinorFooter links are placeholders with no functionality.
"Link 1", "Link 2", "Link 3" have
cursor-pointerstyling suggesting interactivity, but noonClickhandlers or navigation. Either wire up actual navigation or add a TODO comment to track this incomplete work.- <Text className="text-[13px] font-medium cursor-pointer">Link 1</Text> - <Text className="text-[13px] font-medium cursor-pointer">Link 2</Text> - <Text className="text-[13px] font-medium cursor-pointer">Link 3</Text> + {/* TODO: Replace with actual footer navigation links */} + <Text className="text-[13px] font-medium cursor-pointer">Link 1</Text> + <Text className="text-[13px] font-medium cursor-pointer">Link 2</Text> + <Text className="text-[13px] font-medium cursor-pointer">Link 3</Text>Would you like me to open an issue to track completing the footer navigation links?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/FooterNew.jsx` around lines 16 - 20, The three placeholder Text nodes in FooterNew.jsx ("Link 1", "Link 2", "Link 3") are styled as interactive but have no navigation; update each Text (or replace with your app's Link component) to either add proper navigation handlers (e.g., onClick that calls navigate/useRouter.push or href attributes) pointing to their intended routes, or if routes aren't ready add a clear TODO comment and remove the misleading cursor-pointer style; locate the elements inside the Box in the FooterNew component and apply the chosen fix consistently for all three link items.uli-website/src/styles/global.css-1-1 (1)
1-1:⚠️ Potential issue | 🟡 MinorMatch the repository's configured
@importnotation.Stylelint is already flagging Line 1 because this repo expects
@import '…';rather than@import url('…');, so lint will stay red until the import syntax is normalized.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/styles/global.css` at line 1, Change the CSS `@import` to use the repository's expected notation (replace the url(...) form with the plain string form) so the import in global.css matches the lint rule; update the existing `@import` declaration at the top of global.css to use `@import` '<font-URL-or-string>'; ensuring the same font URL string is preserved but without the url(...) wrapper so Stylelint no longer flags the rule.uli-website/src/styles/global.css-24-124 (1)
24-124:⚠️ Potential issue | 🟡 MinorRename the new keyframes to kebab-case or lint will keep failing.
Stylelint flags each new keyframe name here (
fadeUp,fadeIn,fadeRight,scaleIn,borderSlideX,borderSlideY) against the configuredkeyframes-name-pattern. Please rename them and update the matching animation references.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/styles/global.css` around lines 24 - 124, The keyframe names (fadeUp, fadeIn, fadeRight, scaleIn, borderSlideX, borderSlideY) violate the project's keyframes-name-pattern; rename each to kebab-case (e.g., fade-up, fade-in, fade-right, scale-in, border-slide-x, border-slide-y) and update every CSS animation/animation-name reference that uses those identifiers (notably the `@keyframes` declarations and the .border-animate-x, .border-animate-y, .border-animate-x-delay classes and any other places using fadeUp/fadeIn/fadeRight/scaleIn) so the names match exactly.uli-website/src/components/molecules/Projects.jsx-119-120 (1)
119-120:⚠️ Potential issue | 🟡 MinorFix the interpolated class typo in the content column.
Line 120 uses
$${...}, so the conditional class becomes$lg:pl-8instead oflg:pl-8and the extra desktop padding never applies.Suggested fix
- className={`flex flex-col w-full md:w-[60%] lg:w-[65%] gap-8 $${order % 2 != 0 ? "lg:pl-8" : ""}`} + className={`flex flex-col w-full md:w-[60%] lg:w-[65%] gap-8 ${order % 2 !== 0 ? "lg:pl-8" : ""}`}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/Projects.jsx` around lines 119 - 120, The className template in Projects.jsx currently uses "$${...}" causing the literal "$lg:pl-8" to be emitted; update the interpolation in the Box component's className (the template that builds the content column) to use a single "${...}" so the conditional resolves to "lg:pl-8" when order % 2 != 0 instead of "$lg:pl-8".uli-website/src/components/molecules/Announcements.jsx-18-21 (1)
18-21:⚠️ Potential issue | 🟡 MinorRemove the stray
>from the border-image utility.Line 20 turns
[border-image-repeat:round]into a different class token, so that style never gets generated/applied.Suggested fix
- [border-image-repeat:round]> + [border-image-repeat:round]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/Announcements.jsx` around lines 18 - 21, The class string in Announcements.jsx contains a stray ">" after the custom Tailwind utility token `[border-image-repeat:round]` which breaks that token (so the border-image-repeat style is never generated); edit the JSX className where the tokens `[border-image-source:...]`, `[border-image-slice:...]`, `[border-image-repeat:round]`, and `animate-[fadeUp_1.2s_ease-out_forwards]` are declared and remove the trailing ">" so `[border-image-repeat:round]` becomes a single valid class token.uli-website/src/components/molecules/ContentPageShell.jsx-320-322 (1)
320-322:⚠️ Potential issue | 🟡 MinorOnly open external MDX links in a new tab.
This override applies
_blankto internal and hash links too, so in-page anchors and same-site links lose their normal navigation behavior. Limit the extra attributes to external URLs only.Suggested change
a: (props) => ( - <StyledLink target="_blank" rel="noopener noreferrer" {...props} /> + <StyledLink + {...props} + target={/^https?:\/\//.test(props.href || "") ? "_blank" : undefined} + rel={/^https?:\/\//.test(props.href || "") ? "noopener noreferrer" : undefined} + /> ),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/ContentPageShell.jsx` around lines 320 - 322, The custom MDX link renderer currently forces target="_blank" and rel on every anchor; change the a: renderer (the inline function that returns <StyledLink ... />) to only add target="_blank" and rel="noopener noreferrer" when the link is external (e.g., href exists and starts with "http", "//", or "mailto:") and avoid setting those attributes for hash links (href starting with "#") or internal/site-relative links (href starting with "/" or same-origin). Update the renderer to read props.href, branch on those conditions, and pass target/rel only for external cases while preserving original props for internal and anchor links.uli-website/src/components/molecules/RecentBlogs.jsx-30-48 (1)
30-48:⚠️ Potential issue | 🟡 MinorPick the first author separator, not the last one.
The current loop keeps the largest separator index via
Math.max, so"Alice & Bob, Carol"becomes"Alice & Bob et al."instead of"Alice et al.". It also risks matchingandinside a single name. Use the earliest non-negative separator index.Suggested change
function formatAuthor(author) { if (typeof author !== "string") return ""; - let firstDividerIndex = -1; - let dividers = ["&", "and", "And", ","]; - for (let d of dividers) { - let i = author.indexOf(d); - - if (firstDividerIndex === -1) { - firstDividerIndex = Math.max(firstDividerIndex, i); - } else { - firstDividerIndex = Math.max(firstDividerIndex, i); - } - } + const dividerIndexes = [" & ", " and ", " And ", ","] + .map((divider) => author.indexOf(divider)) + .filter((index) => index >= 0); + const firstDividerIndex = dividerIndexes.length + ? Math.min(...dividerIndexes) + : -1; if (firstDividerIndex === -1) return author; - - author = author.substring(0, firstDividerIndex).trim().concat(" et al."); - - return author; + return author.substring(0, firstDividerIndex).trim().concat(" et al."); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/RecentBlogs.jsx` around lines 30 - 48, The formatAuthor function currently picks the largest separator index (Math.max) and can match substrings like "and" inside names; change it to find the earliest non-negative separator index instead of the last one and ensure "and"/"And" are matched as whole words (use a regex word-boundary search) so inputs like "Alice & Bob, Carol" return "Alice et al." and not "Alice & Bob et al."; update the loop in formatAuthor to compute the minimum positive index (ignore -1) or use regex to locate the first separator and then substring up to that position.
🧹 Nitpick comments (8)
uli-website/src/components/molecules/SectionBorders.jsx (1)
7-45: Make decorative border layers non-interactive.These are purely visual overlays; add
pointerEvents: "none"so they never block clicks/taps on nearby section content.Proposed patch
style={{ position: "absolute", + pointerEvents: "none", top: 0, left: 0, right: 0, height: 16, }}Apply the same
pointerEvents: "none"to the left/right/bottom decorative borderBoxstyles as well.Also applies to: 53-93, 102-129
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/SectionBorders.jsx` around lines 7 - 45, The decorative border Box elements (the ones with className "border-animate-x-delay" in SectionBorders.jsx that use backgroundImage '/section-border.svg') are currently interactive and can block clicks; update the style objects for those decorative Boxes (left, right, and any bottom border Boxes around the title) to include pointerEvents: "none" so they never capture pointer events and do not block nearby content interactions.uli-website/src/components/atoms/NavLinkNew.jsx (1)
6-13: Remove stale commented-out NavLink code.This block is dead and adds noise now that
NavLinkNewis the active implementation.Proposed patch
-// // Navlink component for the new design -// export default function NavLink({children, className=""}) { -// return ( -// <Text className={`cursor-pointer hover:text-[`#F28948`] hover:underline #{className}`}>{children}</Text> - -// ) -// }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/atoms/NavLinkNew.jsx` around lines 6 - 13, Remove the stale commented-out NavLink block in NavLinkNew.jsx: delete the old commented export default function NavLink({children, className=""}) { ... } so the file only contains the active NavLinkNew implementation; ensure no other dead commented NavLink code remains and run a quick lint/format to keep the file clean.uli-website/src/components/atoms/DashedButton.jsx (1)
6-6: Consider adding a visible keyboard focus style.Hover/active states are defined, but an explicit
focus-visiblestyle would improve keyboard accessibility consistency.Suggested refactor
- className={`font-labrada bg-transparent cursor-pointer border-[0.5px] border-solid [border-image-source:url('/dashed-btn-bg.png')] [border-image-slice:0%_fill] [border-image-repeat:round] hover:bg-[`#FFC8A6`] active:bg-[`#F28948`] ${className}`} + className={`font-labrada bg-transparent cursor-pointer border-[0.5px] border-solid [border-image-source:url('/dashed-btn-bg.png')] [border-image-slice:0%_fill] [border-image-repeat:round] hover:bg-[`#FFC8A6`] active:bg-[`#F28948`] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[`#F28948`] ${className}`}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/atoms/DashedButton.jsx` at line 6, The button's className in DashedButton.jsx lacks a keyboard focus-visible style; update the className template used in the DashedButton component to include an explicit focus-visible utility (e.g., focus-visible:outline or focus-visible:ring with color/offset) so keyboard users see a clear visible focus state alongside the existing hover/active styles.uli-website/src/components/molecules/FooterNew.jsx (2)
1-4: Remove unused imports.Several imports are unused:
useState,useEffect,useContext,Nav,ResponsiveContext,NavLink, andnavigate. Clean these up to reduce bundle size and improve clarity.-import React, { useState, useEffect, useContext } from "react"; -import { Box, Nav, Text, ResponsiveContext } from "grommet"; -import { NavLink } from "../atoms/UliCore"; -import { navigate } from "gatsby"; +import React from "react"; +import { Box, Text } from "grommet";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/FooterNew.jsx` around lines 1 - 4, The import list contains unused symbols—remove useState, useEffect, useContext, Nav, ResponsiveContext, NavLink, and navigate from the top imports in FooterNew.jsx; keep only the actual used exports (e.g., React plus Box and Text from "grommet") so the component (FooterNew) imports only what it uses and reduces bundle size and dead code.
6-7: Remove dead code.The commented-out
sizevariable (line 7) should be removed if it's not needed.export default function FooterNew() { - // const size = useContext(ResponsiveContext); - return (🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/FooterNew.jsx` around lines 6 - 7, Remove the dead commented code referencing the unused size variable in the FooterNew component: delete the commented line "// const size = useContext(ResponsiveContext);" inside the FooterNew function and, if present, also remove any now-unused imports like ResponsiveContext or useContext to keep the file clean; ensure FooterNew still compiles and runs after removing the dead code.uli-website/src/pages/new-home.js (1)
7-9: Remove unused import.
Resourcesis imported on line 7 but never used (the JSX usage on line 47 is commented out). Line 9 is also a duplicate commented import. Remove the unused import to keep the code clean.import RecentBlogs from "../components/molecules/RecentBlogs"; -import Resources from "../components/molecules/Resources"; import SupportUs from "../components/molecules/SupportUs"; -// import Resources from "../components/molecules/Resources";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/pages/new-home.js` around lines 7 - 9, Remove the unused Resources import and the duplicate commented import: delete the import statement "import Resources from ../components/molecules/Resources" (the one that is unused because the <Resources /> JSX on line ~47 is commented out) and also remove the commented duplicate import line; keep only the needed imports such as SupportUs and ensure there are no remaining references to the Resources symbol in new-home.js.uli-website/src/styles/global.css (1)
86-93: Drop the first duplicate stagger-visible rule.Lines 86-89 keep staggered children hidden, but Lines 90-93 immediately override the exact same selector with the visible state. The first block is dead/confusing.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/styles/global.css` around lines 86 - 93, Remove the duplicate rule that uses the selector ".reveal-stagger.visible > *" which sets opacity: 0 and transform: translateY(16px); and either place the initial hidden state on the non-.visible selector (e.g., ".reveal-stagger > *") or delete the first block so only the visible-state rule remains; update the CSS so the initial hidden state and the visible-state rule are not defined on the identical selector ".reveal-stagger.visible > *" to avoid the dead/overridden declaration.uli-website/src/components/molecules/RecentBlogs.jsx (1)
78-78: Remove the leftover query logging before merge.This will log on every homepage render in production and adds noise to the browser console.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/RecentBlogs.jsx` at line 78, Remove the leftover console.log(data) in the RecentBlogs component so it doesn't log on every homepage render in production; locate the console.log call in RecentBlogs.jsx (inside the RecentBlogs component where data is handled) and delete it (or replace it with a development-only logger guard if you need runtime debugging), ensuring no stray console logging remains before merging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@uli-website/src/components/molecules/Announcements.jsx`:
- Around line 35-43: The component currently contains Figma implementation notes
inside the Text node and a DashedButton that navigates to "/" which is a no-op
on the homepage; update the placeholder announcement copy in Announcements.jsx
by replacing the Text content with the real announcement message, change the
DashedButton content label from "learn more" to the intended CTA text, and
update its onClick (or replace navigate("/")) to the correct target route or
external URL; alternatively, refactor Announcements.jsx to accept props (message
and ctaHref/ctaOnClick) and wire the button to use those props so the live site
won’t ship the placeholder copy or a dead link.
In `@uli-website/src/components/molecules/AppShellNew.jsx`:
- Around line 19-29: The homepage OG title is empty because location.pathname
"/" gets normalized to an empty string and then passed to formatTitle; update
the logic around fullPath/title so that after trimming the trailing "/" and
deriving title (variables fullPath and title) you check if title is falsy (empty
string) or matches the locale list and set title = "Uli" before calling
formatTitle; ensure the same change covers the branch that currently checks
["hi","en","ta","ma"] and that the final title used for the og:title (where
formatTitle is applied) will never be empty.
In `@uli-website/src/components/molecules/ContentPageShell.jsx`:
- Around line 341-349: In formatDate, detect date-only frontmatter (e.g. strings
matching /^\d{4}-\d{2}-\d{2}$/) and treat them as calendar dates in UTC to avoid
local timezone shifts: parse the year/month/day parts and construct the Date via
Date.UTC(year, month-1, day) (or new Date(Date.UTC(...))), then call
toLocaleDateString with a fixed timeZone ('UTC') and the existing day/month/year
options; for non-date-only inputs keep the current parsing but format them with
the same fixed timeZone or leave as-is per project preference so viewers west of
UTC do not see the previous-day result.
In `@uli-website/src/components/molecules/EmailSubscription_Archive.jsx`:
- Around line 20-40: The form currently uses action="#" so submitted emails are
discarded; update the EmailSubscription_Archive component to manage the email
input with React state (e.g., useState for an email value), add an onSubmit
handler on the <form> (replace action="#" with onSubmit), call
event.preventDefault(), validate the email, then perform the submit action
(either call a provided prop like onSubscribe(email) or send a network request
via fetch/axios) and handle success/error UI; ensure the <input> has a name/id
and value/onChange tied to state and the <button> remains type="submit" (and
remove the nonstandard <Text> wrapper) so keyboard/ARIA behavior stays correct.
- Around line 35-40: The email input in the EmailSubscription_Archive component
is using type="text" with no accessible name; change the input to type="email",
add a name attribute and a unique id, and provide an associated visible <label
for="..."> or at minimum an aria-label (e.g., aria-label="Email address") so
screen readers and browser autofill/validation work; update the input referenced
in the component (the input element next to the mail logo and the subscribe
button) and keep existing classes/markup intact.
In `@uli-website/src/components/molecules/NavBarNew.jsx`:
- Line 59: The mobile menu toggle button in NavBarNew.jsx (the button that calls
setOpen and reads open) lacks an accessible name and aria-expanded, so update
that button to provide an accessible label and state: set a dynamic aria-label
(e.g., aria-label={open ? "Close menu" : "Open menu"}), add aria-expanded={open}
and optionally aria-controls pointing to the mobile menu container id (e.g.,
"mobile-menu") so assistive tech knows what it controls; keep the img decorative
(alt="") or remove alt if you rely on the button label.
- Around line 61-70: The NavBarNew component currently uses placeholder anchors
for menu items — replace the NavLinkNew instances for the "Contact" and "Data Y"
items (desktop and mobile variants rendered by NavLinkNew) so they point to real
routes or route constants instead of "#" (update the NavLinkNew with proper
to="/contact" and to="/data-y" or your app's matching route names/route
constants), ensuring both the desktop block around the Box and the mobile menu
blocks use the same real route values.
In `@uli-website/src/components/molecules/Projects.jsx`:
- Around line 18-27: The buttons array in Projects.jsx contains external URLs
but the component's button click handler currently routes all clicks through
Gatsby's navigate(), which only supports internal routes; update the click
handling logic in the Projects component (the handler that calls navigate()) to
detect external URLs (e.g., strings starting with "http://" or "https://") and
use standard navigation (render an anchor <a href="..."> for links or call
window.location.assign(url) for programmatic navigation) for those, while
retaining Gatsby's navigate() for internal routes; also replace the "/#"
placeholder entries in the buttons array with real internal paths or ensure they
are treated as internal routes rather than external.
In `@uli-website/src/components/molecules/RecentBlogs.jsx`:
- Around line 94-108: The row uses a clickable Box with onClick and an inner
Text that also calls navigate(blog.fields.slug), which breaks
keyboard/accessibility and link behaviors; replace the clickable Box with a
semantic anchor/link element (or your routing Link) for the whole row and set
its href to blog.fields.slug, remove the onClick handlers from Box and inner
Text (so only the anchor performs navigation), preserve displayed values from
formatDate(blog.frontmatter.date), blog.frontmatter.name, and
formatAuthor(blog.frontmatter.author), and ensure the anchor supports target/rel
if needed for open-in-new-tab behavior.
- Around line 7-20: The formatDate function currently coerces the input with
Number(input) which turns ISO date strings into NaN and causes "Invalid date"
for every post; change formatDate to parse the ISO string directly (e.g., pass
input into new Date(input) or use Date.parse(input) before new Date) and keep
the existing validation (isNaN(date.getTime())) to handle bad input; also remove
the stray debug console.log(data) in RecentBlogs.jsx so no debug output is left
in production.
In `@uli-website/src/components/molecules/Resources.jsx`:
- Around line 113-122: The resource row uses a clickable Box with onClick and a
nested Text that also has onClick, and the Box isn't keyboard-accessible; update
the interaction to be keyboard-friendly and avoid duplicate navigation: make the
outer Box a semantic interactive element (e.g., render as a <button> or add
role="button" and tabIndex={0}), implement an onKeyDown handler on the Box that
triggers navigate(r.url) for Enter/Space, and remove the nested Text's onClick
(or stop propagation) so only the row-level navigate(r.url) is invoked; keep the
navigate call centralized in the Box's onClick/onKeyDown handlers (referencing
Box, Text, navigate, and r.url).
In `@uli-website/src/components/molecules/SupportUs.jsx`:
- Around line 25-49: The CTA items array currently lacks explicit action
targets, causing the click handler (the onClick for the CTA button that checks
for "email" in the label) to only handle mailto actions and leave "Uli
Community" and "Uli Github" inert; add a clear action field to each object in
items (e.g., url or href with either a full URL or a mailto: link) and then
update the CTA button's click handler (the component's onClick function) to use
that field (open external links with window.open or navigate, and use mailto:
links when the href starts with mailto:) instead of branching on buttonText;
reference the items array and the CTA button onClick handler when making
changes.
- Around line 107-145: Replace the clickable header div with a semantic <button
type="button"> (preserve className, inline styles, onClick={onToggle},
onMouseEnter/onMouseLeave handlers and child components MaskIcon, item.title,
PixelatedArrow) so it becomes keyboard-focusable; add aria-expanded={isOpen} and
aria-controls pointing to the expandable panel id (e.g.
aria-controls={`support-panel-${item.id}`}), give the expandable content
container a matching id and role="region" and optional aria-labelledby
referencing the button id, and ensure you do not remove the browser focus
outline (avoid forcing outline:none) so keyboard users can see focus.
In `@uli-website/src/hooks/useScrollReveal.js`:
- Around line 15-31: The IntersectionObserver block in useScrollReveal's
useEffect can leave elements hidden when the API is unavailable or blocked;
update the effect in useScrollReveal (the useEffect that references ref and
creates a new IntersectionObserver) to detect lack of support and immediately
add the "visible" class (i.e., if typeof IntersectionObserver === "undefined" or
window.IntersectionObserver is falsy) and return early; also add the same
fallback to the second identical useEffect (the other block that observes ref
and toggles "visible") so elements don't remain hidden in browsers/environments
without IntersectionObserver support.
---
Minor comments:
In `@uli-website/src/components/atoms/DashedButton.jsx`:
- Around line 5-8: In the DashedButton.jsx component the rendered <button>
currently has no explicit type, which causes it to act as a submit inside forms;
update the button element in the DashedButton component to include an explicit
type (e.g., type="button") or accept a type prop with a default of "button" so
callers can override it; ensure you update the JSX where className and onClick
are used and preserve existing props and behavior.
In `@uli-website/src/components/molecules/Announcements.jsx`:
- Around line 18-21: The class string in Announcements.jsx contains a stray ">"
after the custom Tailwind utility token `[border-image-repeat:round]` which
breaks that token (so the border-image-repeat style is never generated); edit
the JSX className where the tokens `[border-image-source:...]`,
`[border-image-slice:...]`, `[border-image-repeat:round]`, and
`animate-[fadeUp_1.2s_ease-out_forwards]` are declared and remove the trailing
">" so `[border-image-repeat:round]` becomes a single valid class token.
In `@uli-website/src/components/molecules/ContentPageShell.jsx`:
- Around line 320-322: The custom MDX link renderer currently forces
target="_blank" and rel on every anchor; change the a: renderer (the inline
function that returns <StyledLink ... />) to only add target="_blank" and
rel="noopener noreferrer" when the link is external (e.g., href exists and
starts with "http", "//", or "mailto:") and avoid setting those attributes for
hash links (href starting with "#") or internal/site-relative links (href
starting with "/" or same-origin). Update the renderer to read props.href,
branch on those conditions, and pass target/rel only for external cases while
preserving original props for internal and anchor links.
In `@uli-website/src/components/molecules/FooterNew.jsx`:
- Around line 16-20: The three placeholder Text nodes in FooterNew.jsx ("Link
1", "Link 2", "Link 3") are styled as interactive but have no navigation; update
each Text (or replace with your app's Link component) to either add proper
navigation handlers (e.g., onClick that calls navigate/useRouter.push or href
attributes) pointing to their intended routes, or if routes aren't ready add a
clear TODO comment and remove the misleading cursor-pointer style; locate the
elements inside the Box in the FooterNew component and apply the chosen fix
consistently for all three link items.
In `@uli-website/src/components/molecules/Projects.jsx`:
- Around line 119-120: The className template in Projects.jsx currently uses
"$${...}" causing the literal "$lg:pl-8" to be emitted; update the interpolation
in the Box component's className (the template that builds the content column)
to use a single "${...}" so the conditional resolves to "lg:pl-8" when order % 2
!= 0 instead of "$lg:pl-8".
In `@uli-website/src/components/molecules/RecentBlogs.jsx`:
- Around line 30-48: The formatAuthor function currently picks the largest
separator index (Math.max) and can match substrings like "and" inside names;
change it to find the earliest non-negative separator index instead of the last
one and ensure "and"/"And" are matched as whole words (use a regex word-boundary
search) so inputs like "Alice & Bob, Carol" return "Alice et al." and not "Alice
& Bob et al."; update the loop in formatAuthor to compute the minimum positive
index (ignore -1) or use regex to locate the first separator and then substring
up to that position.
In `@uli-website/src/pages/new-home.js`:
- Line 40: The NavLinkNew instance for "Our Process" uses a placeholder prop
to="#" which doesn't navigate to a real route; update the NavLinkNew element's
to prop to the correct route (e.g., "/our-process" or the actual destination
used elsewhere) or, if the page isn't ready yet, replace the placeholder with a
clear TODO comment and/or link to a pending issue ID to track it (reference the
NavLinkNew component and its to prop).
In `@uli-website/src/styles/global.css`:
- Line 1: Change the CSS `@import` to use the repository's expected notation
(replace the url(...) form with the plain string form) so the import in
global.css matches the lint rule; update the existing `@import` declaration at the
top of global.css to use `@import` '<font-URL-or-string>'; ensuring the same font
URL string is preserved but without the url(...) wrapper so Stylelint no longer
flags the rule.
- Around line 24-124: The keyframe names (fadeUp, fadeIn, fadeRight, scaleIn,
borderSlideX, borderSlideY) violate the project's keyframes-name-pattern; rename
each to kebab-case (e.g., fade-up, fade-in, fade-right, scale-in,
border-slide-x, border-slide-y) and update every CSS animation/animation-name
reference that uses those identifiers (notably the `@keyframes` declarations and
the .border-animate-x, .border-animate-y, .border-animate-x-delay classes and
any other places using fadeUp/fadeIn/fadeRight/scaleIn) so the names match
exactly.
---
Nitpick comments:
In `@uli-website/src/components/atoms/DashedButton.jsx`:
- Line 6: The button's className in DashedButton.jsx lacks a keyboard
focus-visible style; update the className template used in the DashedButton
component to include an explicit focus-visible utility (e.g.,
focus-visible:outline or focus-visible:ring with color/offset) so keyboard users
see a clear visible focus state alongside the existing hover/active styles.
In `@uli-website/src/components/atoms/NavLinkNew.jsx`:
- Around line 6-13: Remove the stale commented-out NavLink block in
NavLinkNew.jsx: delete the old commented export default function
NavLink({children, className=""}) { ... } so the file only contains the active
NavLinkNew implementation; ensure no other dead commented NavLink code remains
and run a quick lint/format to keep the file clean.
In `@uli-website/src/components/molecules/FooterNew.jsx`:
- Around line 1-4: The import list contains unused symbols—remove useState,
useEffect, useContext, Nav, ResponsiveContext, NavLink, and navigate from the
top imports in FooterNew.jsx; keep only the actual used exports (e.g., React
plus Box and Text from "grommet") so the component (FooterNew) imports only what
it uses and reduces bundle size and dead code.
- Around line 6-7: Remove the dead commented code referencing the unused size
variable in the FooterNew component: delete the commented line "// const size =
useContext(ResponsiveContext);" inside the FooterNew function and, if present,
also remove any now-unused imports like ResponsiveContext or useContext to keep
the file clean; ensure FooterNew still compiles and runs after removing the dead
code.
In `@uli-website/src/components/molecules/RecentBlogs.jsx`:
- Line 78: Remove the leftover console.log(data) in the RecentBlogs component so
it doesn't log on every homepage render in production; locate the console.log
call in RecentBlogs.jsx (inside the RecentBlogs component where data is handled)
and delete it (or replace it with a development-only logger guard if you need
runtime debugging), ensuring no stray console logging remains before merging.
In `@uli-website/src/components/molecules/SectionBorders.jsx`:
- Around line 7-45: The decorative border Box elements (the ones with className
"border-animate-x-delay" in SectionBorders.jsx that use backgroundImage
'/section-border.svg') are currently interactive and can block clicks; update
the style objects for those decorative Boxes (left, right, and any bottom border
Boxes around the title) to include pointerEvents: "none" so they never capture
pointer events and do not block nearby content interactions.
In `@uli-website/src/pages/new-home.js`:
- Around line 7-9: Remove the unused Resources import and the duplicate
commented import: delete the import statement "import Resources from
../components/molecules/Resources" (the one that is unused because the
<Resources /> JSX on line ~47 is commented out) and also remove the commented
duplicate import line; keep only the needed imports such as SupportUs and ensure
there are no remaining references to the Resources symbol in new-home.js.
In `@uli-website/src/styles/global.css`:
- Around line 86-93: Remove the duplicate rule that uses the selector
".reveal-stagger.visible > *" which sets opacity: 0 and transform:
translateY(16px); and either place the initial hidden state on the non-.visible
selector (e.g., ".reveal-stagger > *") or delete the first block so only the
visible-state rule remains; update the CSS so the initial hidden state and the
visible-state rule are not defined on the identical selector
".reveal-stagger.visible > *" to avoid the dead/overridden declaration.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 158fe569-5f70-4c45-8aeb-cc02cdb8ec16
⛔ Files ignored due to path filters (19)
.DS_Storeis excluded by!**/.DS_Storeuli-website/.DS_Storeis excluded by!**/.DS_Storeuli-website/package-lock.jsonis excluded by!**/package-lock.jsonuli-website/static/Track_Icons/Database.pngis excluded by!**/*.pnguli-website/static/Track_Icons/Slur Editor.pngis excluded by!**/*.pnguli-website/static/Track_Icons/Tools.pngis excluded by!**/*.pnguli-website/static/Track_Icons/Workshops.pngis excluded by!**/*.pnguli-website/static/cross-icon.svgis excluded by!**/*.svguli-website/static/dashed-btn-bg.pngis excluded by!**/*.pnguli-website/static/hamburger-icon.svgis excluded by!**/*.svguli-website/static/heading.svgis excluded by!**/*.svguli-website/static/mail-logo.svgis excluded by!**/*.svguli-website/static/project-card-bg.svgis excluded by!**/*.svguli-website/static/project-card-logo.svgis excluded by!**/*.svguli-website/static/section-border-vertical.svgis excluded by!**/*.svguli-website/static/section-border.svgis excluded by!**/*.svguli-website/static/subscribe-bar-bg.svgis excluded by!**/*.svguli-website/static/subscribe-btn-bg.pngis excluded by!**/*.pnguli-website/static/top-border.svgis excluded by!**/*.svg
📒 Files selected for processing (53)
.gitignoreuli-website/package.jsonuli-website/src/components/atoms/DashedButton.jsxuli-website/src/components/atoms/NavLinkNew.jsxuli-website/src/components/molecules/AnnouncementBanner.jsxuli-website/src/components/molecules/Announcements.jsxuli-website/src/components/molecules/AppShellNew.jsxuli-website/src/components/molecules/ContentPageShell.jsxuli-website/src/components/molecules/EmailSubscription_Archive.jsxuli-website/src/components/molecules/FooterNew.jsxuli-website/src/components/molecules/NavBarNew.jsxuli-website/src/components/molecules/Projects.jsxuli-website/src/components/molecules/RecentBlogs.jsxuli-website/src/components/molecules/Resources.jsxuli-website/src/components/molecules/SectionBorders.jsxuli-website/src/components/molecules/SupportUs.jsxuli-website/src/hooks/useScrollReveal.jsuli-website/src/pages/about.mdxuli-website/src/pages/blog/Uli-workshop.mdxuli-website/src/pages/blog/approach-data-annotation.mdxuli-website/src/pages/blog/approach.mdxuli-website/src/pages/blog/chisel-online-abuse.mdxuli-website/src/pages/blog/collective-journey.mdxuli-website/src/pages/blog/context-matters.mdxuli-website/src/pages/blog/cross-platform-pt1.mdxuli-website/src/pages/blog/cross-platform_pt_2.mdxuli-website/src/pages/blog/getting-started-with-aws-copilot.mdxuli-website/src/pages/blog/hover-feature-making.mdxuli-website/src/pages/blog/making-of-August-2023.mdxuli-website/src/pages/blog/making-of-dec-2021.mdxuli-website/src/pages/blog/making-of-dec-2023.mdxuli-website/src/pages/blog/making-of-feb-2022.mdxuli-website/src/pages/blog/making-of-jan-2022.mdxuli-website/src/pages/blog/making-of-mar-2022.mdxuli-website/src/pages/blog/responsible-display.mdxuli-website/src/pages/blog/silencing-impact-OGBV.mdxuli-website/src/pages/blog/slurs-occur-every-language.mdxuli-website/src/pages/blog/tech4dev-user-research-lessons.mdxuli-website/src/pages/blog/uli-privacy.mdxuli-website/src/pages/blog/workshop-tech-dev.mdxuli-website/src/pages/faq.mdxuli-website/src/pages/hi/about.mdxuli-website/src/pages/hi/faq.mdxuli-website/src/pages/new-home.jsuli-website/src/pages/privacy-policy.mdxuli-website/src/pages/research.mdxuli-website/src/pages/resources.mdxuli-website/src/pages/ta/about.mdxuli-website/src/pages/ta/faq.mdxuli-website/src/pages/team-2021.mdxuli-website/src/pages/uli-for-ts.mdxuli-website/src/styles/global.cssuli-website/tailwind.config.js
💤 Files with no reviewable changes (1)
- uli-website/src/components/molecules/AnnouncementBanner.jsx
| let fullPath = location.pathname; | ||
| if (fullPath.slice(-1) === "/") { | ||
| fullPath = fullPath.slice(0, -1); | ||
| } | ||
| let title = fullPath.split("/").at(-1); | ||
|
|
||
| if (["hi", "en", "ta", "ma"].includes(title)) { | ||
| title = "Uli"; | ||
| } | ||
|
|
||
| title = formatTitle(title); |
There was a problem hiding this comment.
The homepage og:title resolves to an empty string.
For /, Lines 19-23 normalize the path to "", so title stays empty and Line 51 emits a blank Open Graph title on the homepage. Please default the root/empty case to "Uli" before formatting.
Also applies to: 51-51
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@uli-website/src/components/molecules/AppShellNew.jsx` around lines 19 - 29,
The homepage OG title is empty because location.pathname "/" gets normalized to
an empty string and then passed to formatTitle; update the logic around
fullPath/title so that after trimming the trailing "/" and deriving title
(variables fullPath and title) you check if title is falsy (empty string) or
matches the locale list and set title = "Uli" before calling formatTitle; ensure
the same change covers the branch that currently checks ["hi","en","ta","ma"]
and that the final title used for the og:title (where formatTitle is applied)
will never be empty.
| function formatDate(input) { | ||
| if (!input) return ""; | ||
| const d = new Date(input); | ||
| if (isNaN(d.getTime())) return String(input); | ||
| return d.toLocaleDateString("en-GB", { | ||
| day: "numeric", | ||
| month: "long", | ||
| year: "numeric", | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
node - <<'NODE'
const input = "2021-08-01";
for (const tz of ["UTC", "America/Los_Angeles", "Asia/Kolkata"]) {
console.log(
tz,
new Date(input).toLocaleDateString("en-GB", {
day: "numeric",
month: "long",
year: "numeric",
timeZone: tz,
})
);
}
NODERepository: tattle-made/Uli
Length of output: 136
🏁 Script executed:
#!/bin/bash
node - <<'NODE'
// Test the suggested fix with various inputs
const inputs = [
"2021-08-01", // date-only
"2021-08-01T12:00:00Z", // datetime with Z
"2021-08-01T12:00:00", // datetime without timezone
1627804800000, // timestamp (2021-08-01 00:00:00 UTC)
"invalid-date", // invalid input
"", // empty string
null, // null
"08/01/2021" // different format
];
function formatDateOriginal(input) {
if (!input) return "";
const d = new Date(input);
if (isNaN(d.getTime())) return String(input);
return d.toLocaleDateString("en-GB", {
day: "numeric",
month: "long",
year: "numeric",
});
}
function formatDateFixed(input) {
if (!input) return "";
const normalized =
/^\d{4}-\d{2}-\d{2}$/.test(String(input))
? `${input}T00:00:00Z`
: input;
const d = new Date(normalized);
if (isNaN(d.getTime())) return String(input);
return d.toLocaleDateString("en-GB", {
day: "numeric",
month: "long",
year: "numeric",
timeZone: "UTC",
});
}
console.log("Testing Original vs Fixed in America/Los_Angeles:");
inputs.forEach(input => {
const orig = formatDateOriginal(input);
const fixed = formatDateFixed(input);
console.log(`Input: ${JSON.stringify(input)}`);
console.log(` Original (LA): ${orig}`);
console.log(` Fixed (UTC): ${fixed}`);
console.log();
});
NODERepository: tattle-made/Uli
Length of output: 722
🏁 Script executed:
cd uli-website && grep -r "formatDate" --include="*.jsx" --include="*.js" --include="*.ts" --include="*.tsx" | head -20Repository: tattle-made/Uli
Length of output: 568
🏁 Script executed:
cat -n uli-website/src/components/molecules/RecentBlogs.jsx | grep -A 8 "function formatDate"Repository: tattle-made/Uli
Length of output: 345
🏁 Script executed:
cat -n uli-website/src/pages/blog/index.jsx | grep -B 2 -A 8 "const formatDate"Repository: tattle-made/Uli
Length of output: 506
Preserve the calendar day for date-only frontmatter.
new Date("2021-08-01") is parsed at midnight UTC, then formatted in the viewer's local timezone. For users west of UTC, this renders as 31 July 2021, so post metadata becomes off by one day. Normalize date-only inputs and format them in a fixed timezone.
Suggested change
function formatDate(input) {
if (!input) return "";
- const d = new Date(input);
+ const normalized =
+ /^\d{4}-\d{2}-\d{2}$/.test(String(input))
+ ? `${input}T00:00:00Z`
+ : input;
+ const d = new Date(normalized);
if (isNaN(d.getTime())) return String(input);
return d.toLocaleDateString("en-GB", {
day: "numeric",
month: "long",
year: "numeric",
+ timeZone: "UTC",
});
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@uli-website/src/components/molecules/ContentPageShell.jsx` around lines 341 -
349, In formatDate, detect date-only frontmatter (e.g. strings matching
/^\d{4}-\d{2}-\d{2}$/) and treat them as calendar dates in UTC to avoid local
timezone shifts: parse the year/month/day parts and construct the Date via
Date.UTC(year, month-1, day) (or new Date(Date.UTC(...))), then call
toLocaleDateString with a fixed timeZone ('UTC') and the existing day/month/year
options; for non-date-only inputs keep the current parsing but format them with
the same fixed timeZone or leave as-is per project preference so viewers west of
UTC do not see the previous-day result.
| <form action="#" className="w-full flex justify-center"> | ||
| <div | ||
| className="w-full lg:w-[50%] 2xl:w-[30%] | ||
| border-1 | ||
| border-solid | ||
| [border-image-source:url('/subscribe-bar-bg.svg')] | ||
| [border-image-slice:0%_fill] | ||
| [border-image-repeat:round] | ||
| relative | ||
| flex | ||
| flex-row | ||
| px-3 | ||
| items-center | ||
| " | ||
| > | ||
| <img src="/mail-logo.svg" alt="" /> | ||
| <input | ||
| type="text" | ||
| className="w-full h-10 px-3 outline-none border-none bg-transparent" | ||
| /> | ||
| <button className="border-0 px-5 h-7 text-white bg-[url(/subscribe-btn-bg.png)] cursor-pointer font-labrada"><Text className="text-[13px]">subscribe</Text></button> |
There was a problem hiding this comment.
The subscribe form currently discards the email address.
With action="#" and a default submit button, clicking “subscribe” or pressing Enter just submits back to the same page fragment. There is no submit handler or network action here, so the flow cannot work.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@uli-website/src/components/molecules/EmailSubscription_Archive.jsx` around
lines 20 - 40, The form currently uses action="#" so submitted emails are
discarded; update the EmailSubscription_Archive component to manage the email
input with React state (e.g., useState for an email value), add an onSubmit
handler on the <form> (replace action="#" with onSubmit), call
event.preventDefault(), validate the email, then perform the submit action
(either call a provided prop like onSubscribe(email) or send a network request
via fetch/axios) and handle success/error UI; ensure the <input> has a name/id
and value/onChange tied to state and the <button> remains type="submit" (and
remove the nonstandard <Text> wrapper) so keyboard/ARIA behavior stays correct.
| <img src="/mail-logo.svg" alt="" /> | ||
| <input | ||
| type="text" | ||
| className="w-full h-10 px-3 outline-none border-none bg-transparent" | ||
| /> | ||
| <button className="border-0 px-5 h-7 text-white bg-[url(/subscribe-btn-bg.png)] cursor-pointer font-labrada"><Text className="text-[13px]">subscribe</Text></button> |
There was a problem hiding this comment.
Use a real email field with an accessible label.
The input on Lines 36-39 has no associated label/name and uses type="text", so screen readers get no field name and browsers cannot provide email validation/autofill. This should be type="email" plus a visible label or aria-label.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@uli-website/src/components/molecules/EmailSubscription_Archive.jsx` around
lines 35 - 40, The email input in the EmailSubscription_Archive component is
using type="text" with no accessible name; change the input to type="email", add
a name attribute and a unique id, and provide an associated visible <label
for="..."> or at minimum an aria-label (e.g., aria-label="Email address") so
screen readers and browser autofill/validation work; update the input referenced
in the component (the input element next to the mail logo and the subscribe
button) and keep existing classes/markup intact.
| <Box | ||
| key={idx} | ||
| className=" mx-auto border-t-0 border-r-0 border-l-0 border-b-2 border-dashed border-black/30 flex flex-col lg:flex-row gap-1 lg:gap-6 w-full lg:w-[70%] 2xl:w-[50%] pb-2 hover:bg-[#FFE7D9] active:bg-[#FFC8A6] focus:outline-none focus:ring-0 hover:scale-103 transition-transform duration-300 ease-in-out" | ||
| onClick={() => navigate(blog.fields.slug)} | ||
| > | ||
| <Text className="min-w-[7em] text-xs lg:text-[14px]"> | ||
| {formatDate(blog.frontmatter.date)} | ||
| </Text> | ||
| <Box className="cursor-pointer" style={{ textAlign: "start" }}> | ||
| <Text onClick={() => navigate(blog.fields.slug)} className="font-semibold lg:font-semibold text-[14px] lg:text-[16px]"> | ||
| {blog.frontmatter.name} | ||
| </Text> | ||
| </Box> | ||
| <Box className="lg:text-end" style={{ minWidth: "7em", flexGrow: 1 }}> | ||
| <Text className="text-[13px] lg:text-[14px]">{formatAuthor(blog.frontmatter.author)}</Text> |
There was a problem hiding this comment.
Use a semantic link for each blog row.
The row is clickable only through onClick on a Box, so it is not keyboard reachable and loses normal link behavior like open-in-new-tab/copy-link. The nested title click handler also double-dispatches navigation on title clicks. Render a single anchor/link for the row instead.
Suggested change
- <Box
- key={idx}
- className=" mx-auto border-t-0 border-r-0 border-l-0 border-b-2 border-dashed border-black/30 flex flex-col lg:flex-row gap-1 lg:gap-6 w-full lg:w-[70%] 2xl:w-[50%] pb-2 hover:bg-[`#FFE7D9`] active:bg-[`#FFC8A6`] focus:outline-none focus:ring-0 hover:scale-103 transition-transform duration-300 ease-in-out"
- onClick={() => navigate(blog.fields.slug)}
- >
+ <a
+ key={idx}
+ href={blog.fields.slug}
+ className="mx-auto border-t-0 border-r-0 border-l-0 border-b-2 border-dashed border-black/30 flex flex-col lg:flex-row gap-1 lg:gap-6 w-full lg:w-[70%] 2xl:w-[50%] pb-2 hover:bg-[`#FFE7D9`] active:bg-[`#FFC8A6`] focus:outline-none focus:ring-0 hover:scale-103 transition-transform duration-300 ease-in-out"
+ >
<Text className="min-w-[7em] text-xs lg:text-[14px]">
{formatDate(blog.frontmatter.date)}
</Text>
<Box className="cursor-pointer" style={{ textAlign: "start" }}>
- <Text onClick={() => navigate(blog.fields.slug)} className="font-semibold lg:font-semibold text-[14px] lg:text-[16px]">
+ <Text className="font-semibold lg:font-semibold text-[14px] lg:text-[16px]">
{blog.frontmatter.name}
</Text>
</Box>
<Box className="lg:text-end" style={{ minWidth: "7em", flexGrow: 1 }}>
<Text className="text-[13px] lg:text-[14px]">{formatAuthor(blog.frontmatter.author)}</Text>
</Box>
- </Box>
+ </a>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@uli-website/src/components/molecules/RecentBlogs.jsx` around lines 94 - 108,
The row uses a clickable Box with onClick and an inner Text that also calls
navigate(blog.fields.slug), which breaks keyboard/accessibility and link
behaviors; replace the clickable Box with a semantic anchor/link element (or
your routing Link) for the whole row and set its href to blog.fields.slug,
remove the onClick handlers from Box and inner Text (so only the anchor performs
navigation), preserve displayed values from formatDate(blog.frontmatter.date),
blog.frontmatter.name, and formatAuthor(blog.frontmatter.author), and ensure the
anchor supports target/rel if needed for open-in-new-tab behavior.
| <Box | ||
| key={id} | ||
| className=" cursor-pointer flex flex-row lg:justify-between pb-[5px] pr-2 grow border-t-0 border-r-0 border-l-0 border-b-2 border-dashed border-black/30 hover:bg-[#FFE7D9] active:bg-[#FFC8A6] focus:outline-none focus:ring-0 hover:scale-100 transition-transform duration-100 ease-in-out" | ||
| onClick={() => navigate(r.url)} | ||
| > | ||
| <Text className="w-[30%] md:w-[15%] lg:w-auto text-[14px] lg:text-[16px]">{r.type}</Text> | ||
| <Text | ||
| className="cursor-pointer text-[14px] lg:text-[16px]" | ||
| onClick={() => navigate(r.url)} | ||
| > |
There was a problem hiding this comment.
Use keyboard-accessible interaction for resource rows and avoid double navigation handlers.
The row is a clickable div-like element (Box) without keyboard activation, and the nested Text has another onClick, which can trigger redundant navigation via bubbling.
Proposed patch
<Box
key={id}
className=" cursor-pointer flex flex-row lg:justify-between pb-[5px] pr-2 grow border-t-0 border-r-0 border-l-0 border-b-2 border-dashed border-black/30 hover:bg-[`#FFE7D9`] active:bg-[`#FFC8A6`] focus:outline-none focus:ring-0 hover:scale-100 transition-transform duration-100 ease-in-out"
onClick={() => navigate(r.url)}
+ role="link"
+ tabIndex={0}
+ onKeyDown={(e) => {
+ if (e.key === "Enter" || e.key === " ") {
+ e.preventDefault();
+ navigate(r.url);
+ }
+ }}
>
<Text className="w-[30%] md:w-[15%] lg:w-auto text-[14px] lg:text-[16px]">{r.type}</Text>
- <Text
- className="cursor-pointer text-[14px] lg:text-[16px]"
- onClick={() => navigate(r.url)}
- >
+ <Text className="text-[14px] lg:text-[16px]">
{r.name}
</Text>
</Box>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Box | |
| key={id} | |
| className=" cursor-pointer flex flex-row lg:justify-between pb-[5px] pr-2 grow border-t-0 border-r-0 border-l-0 border-b-2 border-dashed border-black/30 hover:bg-[#FFE7D9] active:bg-[#FFC8A6] focus:outline-none focus:ring-0 hover:scale-100 transition-transform duration-100 ease-in-out" | |
| onClick={() => navigate(r.url)} | |
| > | |
| <Text className="w-[30%] md:w-[15%] lg:w-auto text-[14px] lg:text-[16px]">{r.type}</Text> | |
| <Text | |
| className="cursor-pointer text-[14px] lg:text-[16px]" | |
| onClick={() => navigate(r.url)} | |
| > | |
| <Box | |
| key={id} | |
| className=" cursor-pointer flex flex-row lg:justify-between pb-[5px] pr-2 grow border-t-0 border-r-0 border-l-0 border-b-2 border-dashed border-black/30 hover:bg-[`#FFE7D9`] active:bg-[`#FFC8A6`] focus:outline-none focus:ring-0 hover:scale-100 transition-transform duration-100 ease-in-out" | |
| onClick={() => navigate(r.url)} | |
| role="link" | |
| tabIndex={0} | |
| onKeyDown={(e) => { | |
| if (e.key === "Enter" || e.key === " ") { | |
| e.preventDefault(); | |
| navigate(r.url); | |
| } | |
| }} | |
| > | |
| <Text className="w-[30%] md:w-[15%] lg:w-auto text-[14px] lg:text-[16px]">{r.type}</Text> | |
| <Text className="text-[14px] lg:text-[16px]"> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@uli-website/src/components/molecules/Resources.jsx` around lines 113 - 122,
The resource row uses a clickable Box with onClick and a nested Text that also
has onClick, and the Box isn't keyboard-accessible; update the interaction to be
keyboard-friendly and avoid duplicate navigation: make the outer Box a semantic
interactive element (e.g., render as a <button> or add role="button" and
tabIndex={0}), implement an onKeyDown handler on the Box that triggers
navigate(r.url) for Enter/Space, and remove the nested Text's onClick (or stop
propagation) so only the row-level navigate(r.url) is invoked; keep the navigate
call centralized in the Box's onClick/onKeyDown handlers (referencing Box, Text,
navigate, and r.url).
| return ( | ||
| <div | ||
| onMouseEnter={() => setIsHover(true)} | ||
| onMouseLeave={() => setIsHover(false)} | ||
| onClick={onToggle} | ||
| className="w-full flex flex-col cursor-pointer transition-all duration-300 overflow-hidden" | ||
| style={{ | ||
| backgroundColor: bg, | ||
| ...dashedBorderStyle, | ||
| minHeight: '82px' | ||
| }} | ||
| > | ||
| <div | ||
| className="grid grid-cols-[44px_1fr_32px] md:grid-cols-[44px_1fr_40px] items-center w-full p-[22px] gap-4 md:gap-6" | ||
| style={{ boxSizing: 'border-box' }} | ||
| > | ||
| <div className="flex justify-center flex-shrink-0"> | ||
| <MaskIcon url={item.iconUrl} color={textColor} size={34} /> | ||
| </div> | ||
| <div className="flex-1 min-w-0"> | ||
| <span | ||
| className="text-[19px] md:text-[34px] leading-[1.1em] break-words block w-full" | ||
| style={{ color: textColor, fontFamily: "'XStitch', sans-serif" }} | ||
| > | ||
| {item.title} | ||
| </span> | ||
| </div> | ||
| <div className="flex justify-end flex-shrink-0"> | ||
| <PixelatedArrow color={textColor} isOpen={isOpen} /> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div | ||
| style={{ | ||
| maxHeight: isOpen ? '450px' : '0px', | ||
| opacity: isOpen ? 1 : 0, | ||
| transition: 'max-height 0.4s ease-in-out, opacity 0.3s ease-in-out', | ||
| padding: isOpen ? '0 22px 30px 22px' : '0 22px' | ||
| }} |
There was a problem hiding this comment.
Use a real button for the accordion trigger.
The expandable header is a clickable div, so it is not keyboard-focusable and exposes no expanded/collapsed state. That makes the section unreliable for keyboard and screen-reader users.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@uli-website/src/components/molecules/SupportUs.jsx` around lines 107 - 145,
Replace the clickable header div with a semantic <button type="button">
(preserve className, inline styles, onClick={onToggle},
onMouseEnter/onMouseLeave handlers and child components MaskIcon, item.title,
PixelatedArrow) so it becomes keyboard-focusable; add aria-expanded={isOpen} and
aria-controls pointing to the expandable panel id (e.g.
aria-controls={`support-panel-${item.id}`}), give the expandable content
container a matching id and role="region" and optional aria-labelledby
referencing the button id, and ensure you do not remove the browser focus
outline (avoid forcing outline:none) so keyboard users can see focus.
| useEffect(() => { | ||
| const el = ref.current; | ||
| if (!el) return; | ||
|
|
||
| const observer = new IntersectionObserver( | ||
| ([entry]) => { | ||
| if (entry.isIntersecting) { | ||
| el.classList.add("visible"); | ||
| observer.unobserve(el); // animate only once | ||
| } | ||
| }, | ||
| { threshold, rootMargin } | ||
| ); | ||
|
|
||
| observer.observe(el); | ||
| return () => observer.disconnect(); | ||
| }, [threshold, rootMargin]); |
There was a problem hiding this comment.
Add a fallback for browsers/environments where the observer never runs.
uli-website/src/styles/global.css:63-72 hides .reveal content by default, so if IntersectionObserver is unavailable or blocked, every section using these hooks stays invisible forever. Please add a capability fallback that applies visible immediately.
Also applies to: 43-59
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@uli-website/src/hooks/useScrollReveal.js` around lines 15 - 31, The
IntersectionObserver block in useScrollReveal's useEffect can leave elements
hidden when the API is unavailable or blocked; update the effect in
useScrollReveal (the useEffect that references ref and creates a new
IntersectionObserver) to detect lack of support and immediately add the
"visible" class (i.e., if typeof IntersectionObserver === "undefined" or
window.IntersectionObserver is falsy) and return early; also add the same
fallback to the second identical useEffect (the other block that observes ref
and toggles "visible") so elements don't remain hidden in browsers/environments
without IntersectionObserver support.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
uli-website/src/components/molecules/NavBarNew.jsx (1)
59-59:⚠️ Potential issue | 🟠 MajorAdd accessible name and expanded state to the mobile menu toggle.
Line 59 still lacks an accessible label and expanded/collapse state metadata, so screen-reader users can’t identify control purpose/state.
🛠️ Proposed fix
-<Box flex direction="row" gap="medium" justify="end" align="end" className="lg:hidden" ><button className="bg-inherit m-0 p-0 border-none transition-transform duration-300" onClick={()=>{setOpen(prev => !prev)}}><img src={open ? "/cross-icon.svg" :"/hamburger-icon.svg"} alt="" className={`transition-transform duration-300 ${open ? "rotate-90" : "rotate-0"}`} /></button></Box> +<Box flex direction="row" gap="medium" justify="end" align="end" className="lg:hidden"> + <button + type="button" + className="bg-inherit m-0 p-0 border-none transition-transform duration-300" + aria-label={open ? "Close menu" : "Open menu"} + aria-expanded={open} + aria-controls="mobile-menu" + onClick={() => setOpen(prev => !prev)} + > + <img + src={open ? "/cross-icon.svg" : "/hamburger-icon.svg"} + alt="" + className={`transition-transform duration-300 ${open ? "rotate-90" : "rotate-0"}`} + /> + </button> +</Box>-<Box className={`bg-[`#FFE7D9`] w-full text-center overflow-hidden transition-all duration-300 ease-in-out ${open ? "max-h-96 opacity-100 mt-9 mb-4" : "max-h-0 opacity-0"} lg:hidden`}> +<Box id="mobile-menu" className={`bg-[`#FFE7D9`] w-full text-center overflow-hidden transition-all duration-300 ease-in-out ${open ? "max-h-96 opacity-100 mt-9 mb-4" : "max-h-0 opacity-0"} lg:hidden`}>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/NavBarNew.jsx` at line 59, The mobile menu toggle button in NavBarNew.jsx lacks accessible name and expanded state; update the button (the element that calls setOpen and uses open) to include an accessible label (aria-label or visually-hidden text) that describes its purpose (e.g., "Toggle navigation menu") and add aria-expanded={open} so assistive tech knows its state; also ensure the collapsible menu element has a matching id and add aria-controls on the button pointing to that id so screen readers can associate the control with the menu.
🧹 Nitpick comments (4)
uli-website/src/components/molecules/NavBarNew.jsx (2)
62-64: Remove commented-out navigation code before merge.Keeping old commented blocks in the component adds noise and makes future diffs harder to read.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/NavBarNew.jsx` around lines 62 - 64, Remove the leftover commented navigation block in NavBarNew.jsx (the commented NavLinkNew and Text lines) to clean up the component; locate the commented lines around the NavBarNew render/return and delete the entire commented-out NavLinkNew/ Text fragment so the file contains only active JSX.
15-23: Prevent redundant animation frame scheduling on scroll.Line 16 currently schedules a new
requestAnimationFramefor each scroll event. Coalescing to one in-flight frame avoids unnecessary work during rapid scroll bursts.♻️ Proposed refactor
useEffect(() => { - let rafId; + let rafId = null; + let ticking = false; const handleScroll = () => { - rafId = requestAnimationFrame(() => { + if (ticking) return; + ticking = true; + rafId = requestAnimationFrame(() => { if (borderRef.current) { const scrollY = window.scrollY || window.pageYOffset; // Slow drift: 0.3x scroll speed borderRef.current.style.backgroundPositionX = `${scrollY * 0.3}px`; } + ticking = false; }); }; window.addEventListener("scroll", handleScroll, { passive: true }); return () => { window.removeEventListener("scroll", handleScroll); - cancelAnimationFrame(rafId); + if (rafId !== null) cancelAnimationFrame(rafId); }; }, []);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/NavBarNew.jsx` around lines 15 - 23, handleScroll currently calls requestAnimationFrame on every scroll event causing redundant frames; modify handleScroll to check a shared rafId (already declared) and only call requestAnimationFrame when rafId is null/undefined, store the returned id in rafId, and inside the RAF callback clear rafId (set to null) after updating borderRef.current.style.backgroundPositionX so further scrolls can schedule a new frame; alternatively, call cancelAnimationFrame(rafId) before scheduling and reassign rafId—use the rafId and borderRef symbols to locate and update the logic.uli-website/src/components/molecules/SupportUs.jsx (2)
139-145: Consider a more robust expand/collapse technique.The
maxHeight: 450pxis a magic number that could clip content if descriptions grow longer. For static content this works, but a CSS grid-based approach (grid-template-rows: 0fr/1fr) provides smoother animations without height assumptions.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/SupportUs.jsx` around lines 139 - 145, The inline expand/collapse currently hardcodes maxHeight ('450px') in the SupportUs.jsx div which can clip longer content; replace the size-dependent animation with a grid-based technique: change the container's style logic (the div using isOpen) to use CSS grid row sizing (e.g., toggle between 'gridTemplateRows: "0fr"' and 'gridTemplateRows: "1fr"') and opacity, move transition rules to CSS or a className for smoother animation, and remove the magic maxHeight/padding dependence so the content height grows naturally without clipping.
61-81: Global regex withtest()in a loop is fragile; pattern is also duplicated.The
gflag causes the regex to maintainlastIndexstate betweentest()calls, which can lead to unexpected behavior. Additionally, this same regex pattern is duplicated at line 154.Consider extracting to a module-level constant and using a non-global version for testing:
♻️ Proposed refactor
+// Module-level constant (after imports) +const EMAIL_PATTERN = /[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+/; +const EMAIL_PATTERN_GLOBAL = new RegExp(EMAIL_PATTERN.source, 'gi'); + const HighlightedDescription = ({ text }) => { - const emailRegex = /([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi; - const parts = text.split(emailRegex); + const parts = text.split(new RegExp(`(${EMAIL_PATTERN.source})`, 'gi')); return ( <div className="text-[15px] md:text-[18px] leading-[1.2em] w-full mt-2" style={{ color: "#000000", fontFamily: "'Labrada', serif" }}> {parts.map((part, i) => - emailRegex.test(part) ? ( + EMAIL_PATTERN.test(part) ? ( <aThen at line 154, reuse the constant:
- window.location.href = `mailto:${item.description.match(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi)?.[0] || '[email protected]'}`; + window.location.href = `mailto:${item.description.match(EMAIL_PATTERN_GLOBAL)?.[0] || '[email protected]'}`;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/SupportUs.jsx` around lines 61 - 81, The code uses a global regex with test() inside HighlightedDescription which is brittle and the same pattern is duplicated elsewhere; extract the email pattern to a module-level constant and create two RegExp instances from it: one non-global regex (e.g., EMAIL_TEST_REGEX without the 'g' flag) to use with test() in the parts.map, and another (e.g., EMAIL_SPLIT_REGEX with 'gi') for splitting if needed; replace the inline /.../gi in HighlightedDescription and the duplicated pattern at the other usage (the duplicate around line 154) to use these shared constants so test() does not rely on lastIndex and the pattern is not duplicated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@uli-website/src/components/molecules/NavBarNew.jsx`:
- Around line 50-56: The logo image in NavBarNew.jsx is clickable via an onClick
on the <img>, which is not keyboard-accessible; replace the bare <img> with a
semantic, focusable control (e.g., a <button type="button"> or a react-router
<Link>) that wraps the image so keyboard users can activate it. Update the
element that currently contains the onClick (the img inside Box) to a button
with the same onClick handler (navigate("/")), add an accessible label
(aria-label="Home" or similar), and preserve visual styles by resetting button
default styles (no border/background, padding 0, cursor pointer) so the
appearance stays the same while gaining keyboard/focus support.
---
Duplicate comments:
In `@uli-website/src/components/molecules/NavBarNew.jsx`:
- Line 59: The mobile menu toggle button in NavBarNew.jsx lacks accessible name
and expanded state; update the button (the element that calls setOpen and uses
open) to include an accessible label (aria-label or visually-hidden text) that
describes its purpose (e.g., "Toggle navigation menu") and add
aria-expanded={open} so assistive tech knows its state; also ensure the
collapsible menu element has a matching id and add aria-controls on the button
pointing to that id so screen readers can associate the control with the menu.
---
Nitpick comments:
In `@uli-website/src/components/molecules/NavBarNew.jsx`:
- Around line 62-64: Remove the leftover commented navigation block in
NavBarNew.jsx (the commented NavLinkNew and Text lines) to clean up the
component; locate the commented lines around the NavBarNew render/return and
delete the entire commented-out NavLinkNew/ Text fragment so the file contains
only active JSX.
- Around line 15-23: handleScroll currently calls requestAnimationFrame on every
scroll event causing redundant frames; modify handleScroll to check a shared
rafId (already declared) and only call requestAnimationFrame when rafId is
null/undefined, store the returned id in rafId, and inside the RAF callback
clear rafId (set to null) after updating
borderRef.current.style.backgroundPositionX so further scrolls can schedule a
new frame; alternatively, call cancelAnimationFrame(rafId) before scheduling and
reassign rafId—use the rafId and borderRef symbols to locate and update the
logic.
In `@uli-website/src/components/molecules/SupportUs.jsx`:
- Around line 139-145: The inline expand/collapse currently hardcodes maxHeight
('450px') in the SupportUs.jsx div which can clip longer content; replace the
size-dependent animation with a grid-based technique: change the container's
style logic (the div using isOpen) to use CSS grid row sizing (e.g., toggle
between 'gridTemplateRows: "0fr"' and 'gridTemplateRows: "1fr"') and opacity,
move transition rules to CSS or a className for smoother animation, and remove
the magic maxHeight/padding dependence so the content height grows naturally
without clipping.
- Around line 61-81: The code uses a global regex with test() inside
HighlightedDescription which is brittle and the same pattern is duplicated
elsewhere; extract the email pattern to a module-level constant and create two
RegExp instances from it: one non-global regex (e.g., EMAIL_TEST_REGEX without
the 'g' flag) to use with test() in the parts.map, and another (e.g.,
EMAIL_SPLIT_REGEX with 'gi') for splitting if needed; replace the inline /.../gi
in HighlightedDescription and the duplicated pattern at the other usage (the
duplicate around line 154) to use these shared constants so test() does not rely
on lastIndex and the pattern is not duplicated.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4bcb99da-1aca-4117-88f6-1cd5c4795ca5
⛔ Files ignored due to path filters (4)
uli-website/static/track_icons/Database.pngis excluded by!**/*.pnguli-website/static/track_icons/Slur Editor.pngis excluded by!**/*.pnguli-website/static/track_icons/Tools.pngis excluded by!**/*.pnguli-website/static/track_icons/Workshops.pngis excluded by!**/*.png
📒 Files selected for processing (6)
uli-website/src/components/molecules/Announcements.jsxuli-website/src/components/molecules/FooterNew.jsxuli-website/src/components/molecules/NavBarNew.jsxuli-website/src/components/molecules/Projects.jsxuli-website/src/components/molecules/SupportUs.jsxuli-website/src/pages/new-home.js
✅ Files skipped from review due to trivial changes (2)
- uli-website/src/components/molecules/FooterNew.jsx
- uli-website/src/components/molecules/Announcements.jsx
🚧 Files skipped from review as they are similar to previous changes (2)
- uli-website/src/components/molecules/Projects.jsx
- uli-website/src/pages/new-home.js
| <Box align="center"> | ||
| <img | ||
| src="/Uli_Logo.png" | ||
| alt="Uli Logo" | ||
| style={{ height: "32px", cursor: "pointer" }} | ||
| onClick={() => navigate("/")} | ||
| /> |
There was a problem hiding this comment.
Use a semantic link/button for the clickable logo.
Line 55 attaches navigation to an <img>, which is not keyboard-accessible by default. This is an accessibility blocker for keyboard and assistive-tech users.
🛠️ Proposed fix
- <Box align="center">
- <img
- src="/Uli_Logo.png"
- alt="Uli Logo"
- style={{ height: "32px", cursor: "pointer" }}
- onClick={() => navigate("/")}
- />
- </Box>
+ <Box align="center">
+ <NavLink to="/" aria-label="Go to homepage">
+ <img
+ src="/Uli_Logo.png"
+ alt="Uli Logo"
+ style={{ height: "32px" }}
+ />
+ </NavLink>
+ </Box>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Box align="center"> | |
| <img | |
| src="/Uli_Logo.png" | |
| alt="Uli Logo" | |
| style={{ height: "32px", cursor: "pointer" }} | |
| onClick={() => navigate("/")} | |
| /> | |
| <Box align="center"> | |
| <NavLink to="/" aria-label="Go to homepage"> | |
| <img | |
| src="/Uli_Logo.png" | |
| alt="Uli Logo" | |
| style={{ height: "32px" }} | |
| /> | |
| </NavLink> | |
| </Box> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@uli-website/src/components/molecules/NavBarNew.jsx` around lines 50 - 56, The
logo image in NavBarNew.jsx is clickable via an onClick on the <img>, which is
not keyboard-accessible; replace the bare <img> with a semantic, focusable
control (e.g., a <button type="button"> or a react-router <Link>) that wraps the
image so keyboard users can activate it. Update the element that currently
contains the onClick (the img inside Box) to a button with the same onClick
handler (navigate("/")), add an accessible label (aria-label="Home" or similar),
and preserve visual styles by resetting button default styles (no
border/background, padding 0, cursor pointer) so the appearance stays the same
while gaining keyboard/focus support.
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@uli-website/src/components/molecules/SupportUs.jsx`:
- Around line 141-166: The collapsed panel currently only toggles
maxHeight/opacity (controlled by isOpen) leaving interactive elements like the
button and email link in the tab order and removing focus cues via outline-none;
update the component so when isOpen is false the panel and its children
(HighlightedDescription, the CTA button that checks item.buttonText and mailto
logic, and any link navigation using navigate(item.url)) are truly hidden —
either unmount the panel via conditional rendering (render nothing when isOpen
is false) or add aria-hidden="true" plus visibility: hidden and pointer-events:
none and tabindex="-1" on those interactive elements so they are removed from
keyboard focus; also remove outline-none and replace it with a visible focus
style (e.g., use :focus-visible class) on the CTA button to preserve keyboard
focus indication.
- Around line 153-160: The onClick handler currently uses Gatsby's
navigate(item.url) for all item.url values, which breaks absolute external URLs
(e.g., https://github.com/sponsors/tattle-made); change the logic in the onClick
handler for the SupportUs component so that when item.url is an absolute
external URL you set window.location.href = item.url instead of calling navigate
— keep the existing mailto handling (item.buttonText/email regex) and only
replace navigate(item.url) with a conditional that detects external URLs (or
checks for http/https prefix) and uses window.location.href for externals and
navigate for internal paths.
In `@uli-website/src/pages/blog/index.jsx`:
- Line 21: The Box component in the blog page uses the JSX prop "class" which
prevents Tailwind/Grommet styles from applying; update the Box element in
index.jsx to use "className" instead of "class" (locate the Box with the value
"bg-red-200 p-2 mb-80") so the styling props are recognized by React JSX.
In `@uli-website/src/pages/process.mdx`:
- Around line 18-22: The page copy contains an editorial placeholder "(insert
video currently in research section)" and a truncated sentence starting "While
we keep the values of care and radical inclusion as our north star, we recognize
that in hitting"—replace the placeholder with the intended embedded video or a
stable link and a short caption, and complete the truncated sentence to convey
the full idea (e.g., describe the tradeoffs/challenges faced when
operationalizing those values). Update the "The Uli project..." paragraph to
flow smoothly and ensure the methodology paragraph mentions the award and
related papers clearly; remove any leftover editorial markers before merging.
- Line 20: The phrase "India languages" in the sentence describing the flagship
dataset is a grammatical error; update that phrase to "Indian languages" (or
"languages in India") in the paragraph mentioning the dataset on misogyny to
correct the wording and improve clarity—locate the sentence containing "the
flagship dataset on misogyny in India languages with experts with lived
experience of abuse" and replace "India languages" accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: aa4e158a-884b-4926-a0e3-94a9884fe0cf
📒 Files selected for processing (4)
uli-website/src/components/molecules/SupportUs.jsxuli-website/src/pages/blog/index.jsxuli-website/src/pages/new-home.jsuli-website/src/pages/process.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
- uli-website/src/pages/new-home.js
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
uli-website/src/pages/process.mdx (2)
43-43:⚠️ Potential issue | 🟡 MinorFix wording: “India languages” → “Indian languages”.
Line 43 still has the same grammar issue previously flagged; please update this phrase for readability.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/pages/process.mdx` at line 43, Replace the incorrect phrase "India languages" with "Indian languages" in the sentence starting "The methodology of building the flagship dataset on misogyny in India languages..." in process.mdx so the sentence reads "...dataset on misogyny in Indian languages..."; ensure the change updates only that phrase for readability and grammatical correctness.
45-45:⚠️ Potential issue | 🟠 MajorComplete the truncated closing sentence before merge.
Line 45 is still an unfinished sentence fragment, which leaves the section broken for readers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/pages/process.mdx` at line 45, The sentence fragment "While we keep the values of care and radical inclusion as our north star, we recognize that in hitting" in the process.mdx content is incomplete; complete the closing sentence so the paragraph reads as a full thought (for example finish with an explicit consequence or action like "we may need to make difficult trade-offs and prioritize in the short term to ensure long-term sustainability," or another agreed-upon conclusion). Locate the fragment in src/pages/process.mdx and replace the truncated line with the completed sentence that matches the document tone and intent.
🧹 Nitpick comments (1)
uli-website/src/components/molecules/SupportUs.jsx (1)
151-152: Minor: spacing around operator and focus indicator removed.Line 151 uses
!=0without spaces. Line 152 hasoutline-nonewhich removes the default focus indicator, harming keyboard navigation.✨ Suggested improvements
- {item.buttonText.length!=0 && <button - className="bg-black py-[12px] px-[24px] w-max mt-4 border-none outline-none cursor-pointer hover:bg-[`#333333`] transition-colors active:scale-95 transform" + {item.buttonText.length !== 0 && <button + className="bg-black py-[12px] px-[24px] w-max mt-4 border-none cursor-pointer hover:bg-[`#333333`] transition-colors active:scale-95 transform focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@uli-website/src/components/molecules/SupportUs.jsx` around lines 151 - 152, In SupportUs.jsx, fix the conditional render by spacing and using strict comparison for item.buttonText (e.g., item.buttonText !== 0 or better check length with item.buttonText.length !== 0 or item.buttonText.length > 0) and restore accessible focus styling by removing the "outline-none" utility on the button and replacing it with an accessible focus style (e.g., a visible focus ring class) so keyboard users retain a visible focus indicator.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@uli-website/src/components/molecules/SupportUs.jsx`:
- Around line 63-83: In HighlightedDescription, the emailRegex is declared with
the global flag which makes repeated emailRegex.test(part) calls unreliable
because lastIndex is mutated; change the regex to a non-global pattern (remove
the 'g' flag) or use a fresh RegExp instance for each test, and update the
parts.map logic to call test() against the non-global regex (or use
part.match(emailRegex) without the global flag) so email strings are
consistently detected and rendered as mailto links.
In `@uli-website/src/pages/process.mdx`:
- Around line 33-36: The iframe uses lowercase/deprecated HTML attributes;
update the JSX to use React DOM prop names and non-deprecated usage: replace
frameborder with frameBorder (or remove it and use CSS styling on the iframe
element), change referrerpolicy to referrerPolicy, and replace allowfullscreen
with either the React prop allowFullScreen or ensure fullscreen is enabled via
the allow attribute (e.g., include "fullscreen" in allow). Locate the iframe
element in the file and apply these camelCase updates and/or remove deprecated
attributes in favor of CSS/allow="fullscreen".
---
Duplicate comments:
In `@uli-website/src/pages/process.mdx`:
- Line 43: Replace the incorrect phrase "India languages" with "Indian
languages" in the sentence starting "The methodology of building the flagship
dataset on misogyny in India languages..." in process.mdx so the sentence reads
"...dataset on misogyny in Indian languages..."; ensure the change updates only
that phrase for readability and grammatical correctness.
- Line 45: The sentence fragment "While we keep the values of care and radical
inclusion as our north star, we recognize that in hitting" in the process.mdx
content is incomplete; complete the closing sentence so the paragraph reads as a
full thought (for example finish with an explicit consequence or action like "we
may need to make difficult trade-offs and prioritize in the short term to ensure
long-term sustainability," or another agreed-upon conclusion). Locate the
fragment in src/pages/process.mdx and replace the truncated line with the
completed sentence that matches the document tone and intent.
---
Nitpick comments:
In `@uli-website/src/components/molecules/SupportUs.jsx`:
- Around line 151-152: In SupportUs.jsx, fix the conditional render by spacing
and using strict comparison for item.buttonText (e.g., item.buttonText !== 0 or
better check length with item.buttonText.length !== 0 or item.buttonText.length
> 0) and restore accessible focus styling by removing the "outline-none" utility
on the button and replacing it with an accessible focus style (e.g., a visible
focus ring class) so keyboard users retain a visible focus indicator.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b2cd2731-c6b3-42f3-b049-f78ce376e2a0
⛔ Files ignored due to path filters (3)
uli-website/static/support_icons/database.svgis excluded by!**/*.svguli-website/static/support_icons/support.svgis excluded by!**/*.svguli-website/static/support_icons/workshop.svgis excluded by!**/*.svg
📒 Files selected for processing (3)
uli-website/src/components/molecules/Projects.jsxuli-website/src/components/molecules/SupportUs.jsxuli-website/src/pages/process.mdx
✅ Files skipped from review due to trivial changes (1)
- uli-website/src/components/molecules/Projects.jsx
| const HighlightedDescription = ({ text }) => { | ||
| const emailRegex = /([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi; | ||
| const parts = text.split(emailRegex); | ||
|
|
||
| return ( | ||
| <div className="text-[15px] md:text-[18px] leading-[1.2em] w-full mt-2" style={{ color: "#000000", fontFamily: "'Labrada', serif" }}> | ||
| {parts.map((part, i) => | ||
| emailRegex.test(part) ? ( | ||
| <a | ||
| key={i} | ||
| href={`mailto:${part}`} | ||
| className="underline font-bold hover:opacity-60 transition-opacity" | ||
| onClick={(e) => e.stopPropagation()} | ||
| > | ||
| {part} | ||
| </a> | ||
| ) : part | ||
| )} | ||
| </div> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
Global regex with test() in a loop causes intermittent matching failures.
The emailRegex is declared with the global flag (g), which maintains lastIndex state across test() calls. When iterating over parts in map(), successful matches advance lastIndex, potentially causing subsequent calls to fail on different strings. This can result in emails not being detected as links.
🐛 Proposed fix: use a non-global regex for testing
const HighlightedDescription = ({ text }) => {
const emailRegex = /([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi;
+ const emailTestRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$/i;
const parts = text.split(emailRegex);
return (
<div className="text-[15px] md:text-[18px] leading-[1.2em] w-full mt-2" style={{ color: "#000000", fontFamily: "'Labrada', serif" }}>
{parts.map((part, i) =>
- emailRegex.test(part) ? (
+ emailTestRegex.test(part) ? (
<a
key={i}
href={`mailto:${part}`}
className="underline font-bold hover:opacity-60 transition-opacity"
onClick={(e) => e.stopPropagation()}
>
{part}
</a>
) : part
)}
</div>
);
};🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@uli-website/src/components/molecules/SupportUs.jsx` around lines 63 - 83, In
HighlightedDescription, the emailRegex is declared with the global flag which
makes repeated emailRegex.test(part) calls unreliable because lastIndex is
mutated; change the regex to a non-global pattern (remove the 'g' flag) or use a
fresh RegExp instance for each test, and update the parts.map logic to call
test() against the non-global regex (or use part.match(emailRegex) without the
global flag) so email strings are consistently detected and rendered as mailto
links.
| frameborder="0" | ||
| allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" | ||
| referrerpolicy="strict-origin-when-cross-origin" | ||
| allowfullscreen |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In React JSX, what are the correct <iframe> prop names for frameborder, referrerpolicy, and allowfullscreen?
💡 Result:
In React JSX, the correct prop names for the <iframe> attributes are: - frameborder: frameBorder (deprecated; use CSS border instead) - referrerpolicy: referrerPolicy - allowfullscreen: allowFullScreen (boolean; deprecated in favor of allow="fullscreen") Example: <iframe src="..." frameBorder={0} referrerPolicy="no-referrer" allowFullScreen /> Note: frameborder and allowfullscreen are deprecated HTML attributes. Prefer modern alternatives like CSS for borders and allow="fullscreen" for fullscreen support.
Citations:
- 1: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/iframe
- 2: https://stackoverflow.com/questions/38888461/why-does-setting-the-allowfullscreen-attribute-of-an-iframe-doesnt-seem-to-keep
- 3: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe
- 4: https://www.w3.org/TR/html5/the-iframe-element.html
- 5: https://reactjs.org/docs/dom-elements.html
- 6: https://reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html
- 7: http://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
Use React-correct iframe prop names.
Lines 33–36 use lowercase HTML attribute names in JSX. Switch to React DOM prop casing (camelCase).
Additionally, frameborder and allowfullscreen are deprecated HTML attributes. Consider using CSS for borders and allow="fullscreen" for fullscreen support instead.
Proposed fix
- frameborder="0"
+ frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
- referrerpolicy="strict-origin-when-cross-origin"
- allowfullscreen
+ referrerPolicy="strict-origin-when-cross-origin"
+ allowFullScreen📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| frameborder="0" | |
| allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" | |
| referrerpolicy="strict-origin-when-cross-origin" | |
| allowfullscreen | |
| frameBorder="0" | |
| allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" | |
| referrerPolicy="strict-origin-when-cross-origin" | |
| allowFullScreen |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@uli-website/src/pages/process.mdx` around lines 33 - 36, The iframe uses
lowercase/deprecated HTML attributes; update the JSX to use React DOM prop names
and non-deprecated usage: replace frameborder with frameBorder (or remove it and
use CSS styling on the iframe element), change referrerpolicy to referrerPolicy,
and replace allowfullscreen with either the React prop allowFullScreen or ensure
fullscreen is enabled via the allow attribute (e.g., include "fullscreen" in
allow). Locate the iframe element in the file and apply these camelCase updates
and/or remove deprecated attributes in favor of CSS/allow="fullscreen".
name: UI changes for the homepage
Describe the PR
Made changes to the homepage, added animations, and added new icons.
Summary by CodeRabbit
New Features
UI/Style Updates
Bug Fixes / Cleanup
Chores